当前位置: 首页 > 知识库问答 >
问题:

为什么我的自定义视图的子视图无法在 Marshmallow 中呈现?

廉鸿运
2023-03-14

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

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

在Android 6.0.1中,在Nexus 6和Nexus 6P上,键盘视图可以正确地绘制自身(只是背景颜色)。然而,即使我遍历视图层次结构并强制对每个视图执行无效操作,也不会绘制子键视图。这似乎是Marshmallow特有的。

我不知道在这个版本的Android中是否有新的东西需要说明,或者我是否遇到了错误。

欢迎任何帮助或建议。

代码:

键盘查看

键视图

共有2个答案

马野
2023-03-14

通过 Android 文档建议的自上而下的方法为每个自定义视图正确实现 OnMeasure 和 OnLayout 来修复此问题。

单于山
2023-03-14

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

我们用于键盘渲染的三个主要文件是KeyboardView。cs,键盘视图。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(每行键的容器)

这也扩展了线性布局,并且还具有称为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扩展了<code>视图。KeyView的构造函数被调用,但其<code>OnDraw<code>方法从未被调用/执行:

// 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被调用,但陷入了重复的OnWA ure函数调用(并且有很多键被渲染,所以很快就过时了)。

值得一提的是,我们已经在最新的Nexus 6P智能手机(运行股票Android 6.0Marshmallow)和一台旧的摩托罗拉Droid 4(通过CyanogenMod 13安装Marshmallow)上进行了测试。当我们使用Xamarin Android播放器模拟器(运行Marshmallow)尝试时,它实际上工作了...我的猜测是,模拟器可能会渲染键盘没有问题,因为实际的手机本身要么

(a)以某种方式限制访问

(b)可能会保留旧代码,我们只是还没有完全删除它们的旧. apks

(c)其他一些我没有想到的问题

谢谢你的时间。如果有人能想出一个可能的方向,将不胜感激!

 类似资料:
  • 英文原文:http://emberjs.com/guides/views/customizing-a-views-element 视图在页面上表现为一个单一的DOM元素。通过修改tagName属性,可以改变视图生成的元素的类型。 1 2 3 App.MyView = Ember.View.extend({ tagName: 'span' }); 另外,还可以通过设置一个字符串数组到clas

  • 提前致谢 下面是我的plugin.xml

  • 英文原文:http://emberjs.com/guides/views/defining-a-view/ 你可以使用Ember.View来渲染一个Handlebars模板并将它插入到DOM中。 为了告诉视图要用哪个模板,可以设置它的temaplateName属性。例如,如果我有一个像这样的<script>标签: 1 2 3 4 5 6 7 <html> <head> <script

  • 本文向大家介绍在django admin中添加自定义视图的例子,包括了在django admin中添加自定义视图的例子的使用技巧和注意事项,需要的朋友参考一下 django admin提供了完善的用户管理和数据模型管理,方便实用。研究了一下在admin里面添加自己的页面。 在admin.py里继承django.contrib.admin.ModelAdmin基类 然后在里面写自己的视图处理函数。基

  • 问题内容: 我必须在Android中构建更复杂的自定义视图。最终布局应如下所示: 但是,我只想在XML文件中定义它(不定义SomeView,SomeOtherView等): 这在Android中可行吗?如果可以,那么最干净的方法是什么?我想到的可能解决方案是“重写addView()方法”和“删除所有视图并在以后再次添加它们”,但是我不确定该走哪条路… 在此先感谢您的帮助!:) 问题答案: 绝对有可

  • 我在为我的ListView设置自己的字体时遇到了问题,我不知道如何使用自己的Adapter类以及我需要什么xml(除了我放在ListView中的那个)。我希望(在ListView中)只是水平居中使用自己的字体。那是我的适配器: 它在呼唤ista.java 代码来自StackOverFlow的另一个主题。 > 我在第行中遇到错误(未定义的方法): 字体tf=Typeface.createFromAs