一些额外的细节可以阐明原始帖子:
我们用于键盘渲染的三个主要文件是 KeyboardView.cs、KeyboardRowView.cs 和 KeyView.cs。
KeyboardView(整个键盘的容器)
渲染没有问题。 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();
}
(...和下面的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++;
}
}
(作为一个友好的提醒,我们这样做是因为我们需要一个只能向我们的用户显示某些键/命令的自定义键盘。)
KeyboardRowView(每行键的容器)
这也扩展了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(加载和呈现每个单独键的类)
KeyView 扩展了View 和View.IOnTouchListener。 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;
}
(...和 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);
}
}
我很困惑。 KeyboardView 和 KeyboardRowView 在它们的构造函数/初始化方法中都有一个SetWillNotDraw(false); 函数调用。 KeyView 也有同样的函数调用,成功接收到每个需要渲染的键值。我不明白为什么它只是...不会...绘制...键盘。 (啊。)当我与原始发帖人谈到这一点时,他告诉我所有条件都已满足,才能渲染键盘按键。我尝试附加断点以查看是什么阻止了 KeyView 的 OnDraw 被调用,但陷入了重复的 OnMeasure 函数调用中(并且有很多键被渲染,所以变得老了快 em>)。
值得一提的是,我们已经在最新的 Nexus 6P 智能手机(运行库存的 Android 6.0 Marshmallow)和旧的摩托罗拉 Droid 4(通过 CyanogenMod 13 安装了 Marshmallow)上对其进行了测试。当我们使用 Xamarin Android Player 模拟器(运行 Marshmallow)尝试它时,它实际上工作......我的猜测是模拟器可能没有问题地渲染键盘,因为实际的手机本身要么是
(a) 以某种方式限制访问
(b) 可能会保留旧代码,我们只是还没有完全删除他们的旧 .apks
(c) 其他一些我没有想到的问题
感谢您的宝贵时间。如果有人能想到一个可能的方向,将不胜感激!