【问题标题】:Why won't the child views of my custom view render in Marshmallow?为什么我的自定义视图的子视图不会在 Marshmallow 中呈现?
【发布时间】:2016-04-12 00:25:18
【问题描述】:

我正在使用 Xamarin 开发自定义键盘。

我的键盘视图对视图容器本身及其子键视图都有一个重写的 OnDraw()。我还在为每个视图适当地使用 SetWillNotDraw(false)。它目前在我的 Nexus 10 平板电脑上的 5.0.1 中运行良好。

在 Android 6.0.1 中,在 Nexus 6 和 Nexus 6P 上,键盘视图正确地绘制自身(只是背景颜色)。然而,子键视图永远不会被绘制,即使我遍历视图层次结构并强制每个视图无效。这似乎是棉花糖特有的。

我不知道在这个版本的 Android 中我是否需要考虑一些新的问题,或者我是否遇到了错误。

欢迎任何帮助或建议。

代码:

KeyboardView

KeyView

【问题讨论】:

  • 基本上你在问:“为什么我的代码不起作用”,但没有提供任何信息。有人很难猜测发生了什么。查看问题跟踪器,我没有看到有人对不绘图的东西有问题。
  • 我在帖子底部提供了代码。

标签: android xamarin xamarin.android android-custom-view android-6.0-marshmallow


【解决方案1】:

已通过 Android 文档建议的自上而下方法为每个自定义视图正确实施 OnMeasure 和 OnLayout 进行修复。

【讨论】:

    【解决方案2】:

    一些额外的细节可以阐明原始帖子:

    我们用于键盘渲染的三个主要文件是 KeyboardView.csKeyboardRowView.csKeyView.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 扩展了ViewView.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);
            }
        }
    

    我很困惑。 KeyboardViewKeyboardRowView 在它们的构造函数/初始化方法中都有一个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) 其他一些我没有想到的问题

    感谢您的宝贵时间。如果有人能想到一个可能的方向,将不胜感激!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多