繁体   English   中英

Android View实例化订单

[英]Android View Instantiation Order

编辑:我错过了一个关键概念,消息队列,同时创建我的自定义视图并尝试更新视图而不使用它原来是我遇到的问题的根源。 这在这里被清除:

Android:编写支持Message Queue的自定义视图

事实证明,你需要让运行时/ android在OnCreate退出后调用OnMeasure(“正常”),并且同时通过.post方法将任何更新放到消息队列中。

因此,您可以像往常一样在OnCreate中通过FindViewById获取视图的句柄,然后在runnable中发布任何更新(通过setText或您自己的set函数覆盖)(参见上面的链接)。


我已经在android中开发了一个自定义视图已经有一段时间了,并且已经完成了构造函数,属性,布局参数和绘图方法(OnMeasure,OnLayout,...)的实验。

最父视图组(在布局文件中声明用于渲染的视图组)继承自RelativeLayout并包含三个子视图,所有自定义/继承的视图组也是如此,依此类推。

我正在实现一个自定义日历(我知道,非常原创和令人兴奋),我将调用CustomCalendar。 所以,在我的布局文件中,我有这个声明

<MonoDroid.CustomViews.CustomCalendar
  xmlns:calendar="http://schemas.android.com/apk/res/net.monocross.appname"
  android:id="+id/Calendar1"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  calendar:row_count="5"
  calendar:col_count="7"
 ...
/>

此视图与布局文件中定义的其他一些视图一起存在,因此也是我的复杂功能的来源,现在将说明。

我试图弄清楚如何在OnMeasure被调用之前得到这个视图的尺寸(我可以在那里得到它们没有问题,但是因为子视图的布局尺寸是从这个视图尺寸确定的,所以我无法实例化孩子的视图直到第一次调用OnMeasure,这证明是在我需要它之后;在OnCreate退出之后)。

也就是说,在OnCreate中调用SetContentView,然后通过FindViewById(Resource.Id.Calendar1)从中实例化自定义视图后,如果从OnMeasure覆盖完成,则子视图也不会被实例化(再次,b / c OnMeasure)直到OnCreate返回后才调用)。

如果我读取传递给构造函数的属性,那么我从layout_width和layout_height获得的所有内容都是fill_parent的常量-1。 我也不能只使用整个屏幕,因为还有其他视图可以补偿。


因此,我正在寻找从其构造函数中确定自定义视图的维度的最佳方法,以便我可以使用适当的布局维度从它(构造函数)实例化所有视图的childern,以便可以从调用SetContentView之后和从OnCreate返回之前的OnCreate(用于更新内容)。

对于同一目的的另一种方法对我来说没问题,尽管我有点想要按照基础设施的意图去做(如果有这样的事情)。

您无法在构造函数中获取维度。 最好的情况是,如果它们是用XML定义的,您可以从AttributeSet获取布局宽度和高度。

你应该做的是压倒onMeasure和onLayout。 您可以在onMeasure中执行所需的任何计算和设置,然后将计算值传递给measureChild(view, widthSpec, heightSpec) 你可以搞乱onLayout中的布局内容然后调用childView.layout(left, top, right, bottom)

我想我有这个问题。 我不确定自己的时间,但我做了以下工作以获得尺寸

ViewTreeObserver viewTreeObserver = mOverlayFrameLayout.getViewTreeObserver();
                if (viewTreeObserver.isAlive()) {
                  viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
                    public void onGlobalLayout() {
                        mOverlayFrameLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        //do some things
                    }
                  });
                }

编辑不要这样做(参见OP的编辑说明)。


它最终是onMeasure是解决这个问题的地方......

Ya只需要在OnCreate的视图上调用Measure,这需要构建Measure使用的宽度和高度MeasureSpec参数:

public class Activity1 : Activity
{
    ...

    private CustomCalendar _calendar;

    public override void OnCreate()
    {
        SetContentView(Resource.Layout.Calendar);

        _calendar = FindViewById<CustomCalendar>(Resource.Id.Calendar1);           

        int widthMeasureSpec = View.MeasureSpec.MakeMeasureSpec(Resources.DisplayMetrics.WidthPixels, MeasureSpecMode.Exactly);
        int heightMeasureSpec = View.MeasureSpec.MakeMeasureSpec(Resources.DisplayMetrics.HeightPixels, MeasureSpecMode.Exactly);

        _calendar.Measure(widthMeasureSpec, heightMeasureSpec);

        ...
    }
}

然后只是递归地对所有嵌套/子视图执行相同的操作。

我在每个自定义视图中都有一个静态bool变量,用于跟踪视图是否已初始化,并在onMeasure中检查它以确定是否应该初始化和测量它们。

    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        base.OnMeasure(widthMeasureSpec, heightMeasureSpec);

        if (!_initialized)
        {
            _WIDTH = MeasureSpec.GetSize(widthMeasureSpec);
            _HEIGHT = MeasureSpec.GetSize(heightMeasureSpec);

            InitViews();

            MeasureSpecMode widthMode = MeasureSpec.GetMode(widthMeasureSpec);
            MeasureSpecMode heightMode = MeasureSpec.GetMode(heightMeasureSpec);

            widthMeasureSpec = MeasureSpec.MakeMeasureSpec(_childView.LayoutParameters.Width, widthMode);
            heightMeasureSpec = MeasureSpec.MakeMeasureSpec(_childView.LayoutParameters.Height, heightMode);

            _childView.Measure(widthMeasureSpec, heightMeasureSpec);

            _initialized = true;
        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM