Xamarin动态添加按钮未显示

时间:2017-10-23 18:12:12

标签: c# android multithreading xamarin xamarin.android

我一直在编写一个Android应用程序,它在从服务器接收数据时生成动态视图。

我发现当在另一个线程内部尝试创建视图时,不会显示按钮,但会显示线性布局。

例如,以下内容不起作用......

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        Task thread = new Task(() =>
        {
            RunOnUiThread(() =>
            {
                ShowDynamicLayout();
            });
        });
        thread.Start();
        return;
    }

但这确实......

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        ShowDynamicLayout();
        return;
    }

ShowDynamicView:

    private void ShowDynamicLayout()
    {
        var scrollView = new ScrollView(this)
        {
            LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent)
        };

        var mainLayout = new LinearLayout(this)
        {
            Orientation = Orientation.Vertical,
            LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent)

        };

        scrollView.AddView(mainLayout);

        for (int n = 1; n < 10; n++)
        {
            var dv = new DynamicView(this, n)
            {
                LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, 100)
            };
            mainLayout.AddView(dv);
        }

        SetContentView(scrollView);
    }

DynamicView:

public class DynamicView : LinearLayout
{
    private List<LinearLayout> layouts;

    public DynamicView(Context context, int count) :
        base(context)
    {
        this.Initialize(count);
    }

    protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
    {
        base.OnSizeChanged(w, h, oldw, oldh);

        foreach (var l in this.layouts)
        {
            l.LayoutParameters = new LinearLayout.LayoutParams(w / this.layouts.Count, ViewGroup.LayoutParams.WrapContent);
        }
    }

    private void Initialize(int count)
    {
        this.Orientation = Orientation.Horizontal;
        this.SetBackgroundColor(new Color(0, 125, 0));
        layouts = new List<LinearLayout>();
        for (int n = 0; n < count; n++)
        {
            var layout = new LinearLayout(this.Context)
            {
                Orientation = Orientation.Vertical,
                LayoutParameters =
                    new LinearLayout.LayoutParams(this.Width / count, ViewGroup.LayoutParams.WrapContent)
            };

            layouts.Add(layout);

            var button = new Button(this.Context)
            {
                Text = "New button"
            };
            button.SetBackgroundColor(new Color(125, 0, 0));
            layout.AddView(button);

            this.AddView(layout);
        }
    }
}

无螺纹: http://www.crashm.co.uk/Working.PNG

螺纹: http://www.crashm.co.uk/NotWorking.PNG

1 个答案:

答案 0 :(得分:1)

  

我发现当尝试在不同的线程内创建视图时,按钮不会显示,但会显示线性布局。

我不知道根深蒂固的原因,但似乎你的代码是由没有线程的android系统执行的。 Android重新渲染您的视图。(您可以在OnDraw上设置断点时查看它,并检查线程和非线程的中断时间差异。)

无论如何,问题在于以下几行:

LayoutParameters =new LinearLayout.LayoutParams(this.Width / count, ViewGroup.LayoutParams.WrapContent)

在Initialize函数中,因为它在OnCreate中调用,所以此时this.Width始终为0,因为此视图尚未被测量。因此,你不会得到预期的观点。

<强>解决方案:

您应该将初始化和渲染逻辑分开并在OnDraw中调用渲染逻辑,如下所示:

public class DynamicView : LinearLayout
{
    private List<LinearLayout> layouts;
    int count;
    public DynamicView(Context context, int count) :
        base(context)
    {
        this.count = count;
    }

    protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
    {
        base.OnSizeChanged(w, h, oldw, oldh);
        this.Initialize(count);

            foreach (var l in this.layouts)
            {
                l.LayoutParameters = new LinearLayout.LayoutParams(w / this.layouts.Count, ViewGroup.LayoutParams.WrapContent);
            }
    }


    protected override void OnDraw(Canvas canvas)
    {
        base.OnDraw(canvas);
        //call the render logic in OnDraw
        FillView();
    }

    private void Initialize(int count)
    {
        //initialize logic
        this.Orientation = Orientation.Horizontal;
        this.SetBackgroundColor(new Color(0, 125, 0));
        layouts = new List<LinearLayout>();
    }

    //render logic
    private void FillView()
    {
        for (int n = 0; n < count; n++)
        {
            var layout = new LinearLayout(this.Context)
            {
                Orientation = Orientation.Vertical,
                Background = new ColorDrawable(new Color(0, 10, 0)),
                LayoutParameters =
                    new LinearLayout.LayoutParams(this.Width / count, ViewGroup.LayoutParams.WrapContent)
            };

            layouts.Add(layout);

            var button = new Button(this.Context)
            {
                Text = "New button"
            };
            button.SetBackgroundColor(new Color(125, 0, 0));
            layout.AddView(button);

            this.AddView(layout);
        }
    }
}