[英]Why won't the child views of my custom view render in Marshmallow?
I'm developing a custom keyboard using Xamarin. 我正在使用Xamarin开发自定义键盘。
My keyboard view has an overridden OnDraw() for both the view container itself and it's child key views. 我的键盘视图的视图容器本身及其子键视图都有一个重写的OnDraw()。 I'm also using SetWillNotDraw(false) appropriately for each view.
我还为每个视图适当地使用SetWillNotDraw(false)。 It currently works beautifully in 5.0.1 on my Nexus 10 tablet.
目前,在我的Nexus 10平板电脑上的5.0.1版本中,它运行良好。
In Android 6.0.1, on a Nexus 6 and a Nexus 6P, the keyboard view correctly draws itself (just a background color). 在Android 6.0.1中,在Nexus 6和Nexus 6P上,键盘视图会正确绘制自身(只是背景颜色)。 The child key views however are never drawn, even if I iterate through the view hierarchy and force an invalidate on each one.
但是,即使我遍历视图层次结构并对每个视图强制无效,也不会绘制子键视图。 This seems to be specific to Marshmallow.
这似乎是棉花糖特有的。
I don't know if there's something new I need to account for in this version of Android or if I'm encountering a bug. 我不知道在此版本的Android中是否需要解决一些新问题,或者是否遇到错误。
Any help or suggestions are welcome. 欢迎任何帮助或建议。
Code: 码:
Some extra details to shed light on the original post: 一些额外的细节可以阐明原始帖子:
The three major files we use for keyboard rendering are KeyboardView.cs , KeyboardRowView.cs , and KeyView.cs . 我们用于键盘渲染的三个主要文件是KeyboardView.cs , KeyboardRowView.cs和KeyView.cs 。
KeyboardView (the container for the whole keyboard) KeyboardView (整个键盘的容器)
This has no trouble rendering. 渲染没有问题。 KeyboardView extends a
LinearLayout
and its OnDraw
method runs, calling a Build()
function to create what it needs (just a basic background which will "hold" the individual keys): KeyboardView扩展了
LinearLayout
并运行其OnDraw
方法,并调用Build()
函数来创建所需的内容(只是一个基本背景,它将“保留”各个键):
protected override void OnDraw(Canvas canvas)
{
Build();
base.OnDraw(canvas);
// background
Paint bg = new Paint(PaintFlags.AntiAlias);
bg.Color = BG; // light blue
canvas.DrawRect(0, 0, MeasuredWidth, Height, bg);
InvalidateKeys();
}
(...and Build()
below...) (...以及下面的
Build()
...)
public void Build()
{
// only build once
if (keyLayout != null)
return;
// clear out children
RemoveAllViews();
// define sizes of stuff
if (isPortrait)
{
keyMargin = (int)(MeasuredWidth * .01f);
}
else
{
keyMargin = (int)(MeasuredHeight * .01f);
}
keyWidth = (MeasuredWidth - (keyMargin * 2)) / keyboard.MaxCols;
keyHeight = (MeasuredHeight - (keyMargin * 2)) / keyboard.Rows.Count;
// set general padding around keyboardview
SetPadding(keyMargin, keyMargin, keyMargin, keyMargin);
// build KeyLayout from the keyboard object
keyLayout = new List<List<KeyView>>();
int idx = 0;
foreach (List<Key> row in keyboard.Rows)
{
keyLayout.Add(new List<KeyView>());
// create and add new KeyboardRowView
KeyboardRowView krv = new KeyboardRowView(Context, this, idx);
AddView(krv);
// figure out if we need a margin offset for this row
int extraMargin = 0;
int numCols = CountRowCols(row);
if (numCols < keyboard.MaxCols)
{
// measure full width of the button container and the total row margin
int rowWidth = (int)(numCols * keyWidth);
int rowMargin = MeasuredWidth - (keyMargin * 2) - rowWidth;
// add the offset
extraMargin = rowMargin / 2;
}
// build keys and add them to keyLayout and KeyboardRowView
int idx2 = 0;
foreach (Key key in row)
{
int leftMargin = idx2 == 0 ? extraMargin : 0;
KeyView kv = new KeyView(Context, this, key, leftMargin);
keyLayout[idx].Add(kv);
krv.AddView(kv);
idx2++;
}
idx++;
}
}
(As a friendly reminder, we're doing this because we need a custom keyboard which can only display certain keys/commands to our users.) (提醒您,我们这样做是因为我们需要一个自定义键盘,该键盘只能向用户显示某些键/命令。)
KeyboardRowView (the container for each row of keys) KeyboardRowView (每行按键的容器)
This also extends a LinearLayout
, and also has its OnDraw
method called: 这也扩展了
LinearLayout
,还具有其OnDraw
方法,称为:
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
Paint paint = new Paint();
paint.SetARGB(255, 0, 0, 0);
paint.SetStyle(Paint.Style.Stroke);
paint.StrokeWidth = 3;
canvas.DrawRGB(255, 255, 255);
canvas.DrawRect(0, 0, 100, 100, paint);
}
KeyView (the class which loads and renders each individual key) KeyView (加载和呈现每个单独键的类)
KeyView extends View
and View.IOnTouchListener
. KeyView扩展了
View
和View.IOnTouchListener
。 KeyView's constructor is called, but its OnDraw
method is never called/executed: 调用了KeyView的构造函数,但从未调用/执行过其
OnDraw
方法:
// key views are always dynamically created
public KeyView(Context ctx, KeyboardView parent, Key k, int leftMargin)
: base(ctx)
{
// make sure the key will draw
SetWillNotDraw(false);
keyboard = parent;
key = k;
isDown = false;
// check for an overridden span to adjust width, if needed
int span = string.IsNullOrEmpty(key.Span) ? 1 : Convert.ToInt32(key.Span);
int keyWidth = keyboard.keyWidth + ((span - 1) * keyboard.keyWidth);
width = keyWidth;
height = keyboard.keyHeight;
// set margin
var parameters = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WrapContent,
LinearLayout.LayoutParams.MatchParent
);
parameters.LeftMargin = leftMargin;
LayoutParameters = parameters;
// set touch listener
SetOnTouchListener(this);
// enable haptic feedback for button presses
HapticFeedbackEnabled = true;
}
(...and OnDraw) (...和OnDraw)
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
KeyState primary = key.Primary;
KeyState secondary = key.Secondary;
if (keyboard.swapped)
{
primary = key.Secondary != null ? key.Secondary : key.Primary;
secondary = key.Secondary != null ? key.Primary : null;
}
if (keyboard.shifted)
{
if (primary.Shift != null)
primary = primary.Shift;
if (secondary != null && secondary.Shift != null)
secondary = secondary.Shift;
}
// figure out what color the key is supposed to be
Paint bg = new Paint(PaintFlags.AntiAlias);
bg.Color = GetKeyBgColor(key.Style);
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop)
canvas.DrawRoundRect(keyboard.keyMargin, keyboard.keyMargin, width - keyboard.keyMargin, height - keyboard.keyMargin, keyboard.keyMargin, keyboard.keyMargin, bg);
else
canvas.DrawRoundRect(new RectF(keyboard.keyMargin, keyboard.keyMargin, width - keyboard.keyMargin, height - keyboard.keyMargin), keyboard.keyMargin, keyboard.keyMargin, bg);
// draw primary key state
Paint fg = new Paint(PaintFlags.AntiAlias);
fg.TextSize = height * .5f;
fg.Color = GetKeyFgColor(key.Style);
string character = string.IsNullOrEmpty(primary.Character) ? "#" : primary.Character;
int charWidth = Convert.ToInt32(fg.MeasureText(character));
int charX = (width - charWidth) / 2;
canvas.DrawText(character, charX, (height * .7f), fg);
// draw secondary key state
if (secondary != null)
{
fg.TextSize = height * .25f;
fg.Color = GetKeyFgColor(key.Style, true);
character = string.IsNullOrEmpty(secondary.Character) ? "#" : secondary.Character;
charWidth = Convert.ToInt32(fg.MeasureText(character));
charX = width - charWidth - (keyboard.keyMargin * 2);
canvas.DrawText(character, charX, (height * .35f), fg);
}
}
I am confused. 我很困惑。 Both KeyboardView and KeyboardRowView have a
SetWillNotDraw(false);
KeyboardView和KeyboardRowView都具有
SetWillNotDraw(false);
function call in their constructor/initialization methods. 在其构造函数/初始化方法中调用函数。 KeyView also has the same function call, and successfully receives each key value that needs to be rendered.
KeyView也具有相同的函数调用,并成功接收需要呈现的每个键值。 What I don't get is why it just...won't...draw...the...keyboard.
我不明白的是为什么它只是...不会...绘制...键盘。 (Argh.) When I spoke with the original poster about this, he told me that all the conditions have been met in order for the keyboard keys to be rendered.
(Argh。)当我与原始海报商谈此事时,他告诉我所有条件都已得到满足,以便呈现键盘键。 I tried attaching breakpoints to see what was preventing KeyView's
OnDraw
from being called, but got caught up in repeated OnMeasure
function calls (and there are a lot of keys that get rendered, so that got old quick ). 我尝试附加断点以查看阻止调用KeyView的
OnDraw
的原因,但是陷入了重复的OnMeasure
函数调用中(并且渲染了很多键,因此很快就变老了)。
It's worth mentioning that we've tested it on the latest Nexus 6P smartphone (running stock Android 6.0 Marshmallow) and an old Motorola Droid 4 (with Marshmallow installed via CyanogenMod 13). 值得一提的是,我们已经在最新的Nexus 6P智能手机(运行时的Android 6.0棉花糖) 和旧版的Motorola Droid 4(通过CyanogenMod 13安装了棉花糖)上进行了测试。 When we tried it using a Xamarin Android Player emulator (running Marshmallow), it actually worked ... my guess is that the emulator might be rendering the keyboard with no problem because the actual phones themselves are either
当我们使用Xamarin Android Player模拟器(运行棉花糖)进行尝试时,它实际上可以工作 ……我的猜测是,模拟器可能毫无问题地渲染了键盘,因为实际的手机本身就是
(a) restricting access somehow (a)以某种方式限制访问
(b) potentially holding on to old code and we just haven't completely removed their old .apks (b)可能会保留旧代码,而我们还没有完全删除它们的旧.apks
(c) some other issue I haven't thought of (c)我没有想到的其他问题
Thank you for your time. 感谢您的时间。 If anyone can think of a possible direction to go in, it would be appreciated!
如果有人能想到一个可行的方向,将不胜感激!
通过使用Android文档建议的自上而下方法为每个自定义视图正确实现OnMeasure和OnLayout进行了修复。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.