C# Android视图实例化顺序

C# Android视图实例化顺序,c#,android,mobile,xamarin.android,C#,Android,Mobile,Xamarin.android,编辑:我在创建自定义视图并尝试在不使用视图的情况下更新视图时,缺少了一个关键概念,即消息队列,结果证明这是我遇到的问题的根源。这在这里得到澄清: 事实证明,您需要让OnCreate退出后的runtime/android调用OnMeasure(“像正常情况一样”),同时通过.post方法在消息队列中对视图进行任何更新 因此,您可以通过FindViewById,像往常一样在OnCreate中获取视图的句柄,然后 对其发布任何更新(通过诸如setText之类的覆盖或您自己的set函数) 在runna

编辑:我在创建自定义视图并尝试在不使用视图的情况下更新视图时,缺少了一个关键概念,即消息队列,结果证明这是我遇到的问题的根源。这在这里得到澄清:

事实证明,您需要让OnCreate退出后的runtime/android调用OnMeasure(“像正常情况一样”),同时通过.post方法在消息队列中对视图进行任何更新

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


我在android上开发自定义视图已经有相当一段时间了,并且对构造函数、属性、布局参数和绘图方法(OnMeasure、OnLayout等)进行了全面的实验

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

我正在实现一个自定义日历(我知道,非常新颖和激动人心),我将调用CustomCalendar。所以,在我的布局文件中,我有station

<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覆盖完成的,则不会实例化它(同样,直到OnCreate返回后才调用b/c OnMeasure)

如果我读取传递到构造函数中的属性,我从布局宽度和布局高度得到的所有值都是填充父项的常数-1。我也不能只使用整个屏幕,因为还有其他视图需要补偿


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


另一种达到相同目的的方法对我来说也没问题,尽管我希望按照基础设施的预期方式来做(如果有这样的事情)。

你不能在构造函数中获得维度。如果它们是用XML定义的,你最多可以从属性集获得布局宽度和高度


你应该做的是覆盖onMeasure和onLayout。你可以在onMeasure中进行任何需要的计算和设置,然后将计算值传递给
measureChild(view,widthSpec,heightSpec)
。你可以在onLayout中处理布局内容,然后调用
childView.layout(左、上、右、下)

我想我遇到了这个问题。我自己也不确定时间,但我做了以下操作来获得尺寸

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

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


结果是,onMeasure就是解决这个问题的地方

您只需要从OnCreate调用视图上的Measure,这需要构建 宽度和高度测量测量使用的参数:

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);

        ...
    }
}

好的,你肯定只是在我的谜题中添加了一个缺失的部分,并为我澄清了一些误解。但是,我不确定这是否能解决OP描述的问题(我不会在这里背诵,lol)。我将对此进行实验。谢谢。从这听起来,OnMeasure是我应该初始化我的孩子视图的地方(并对其调用measureChild)。如果是这种情况,那么我应该从主要活动的哪个生命周期方法获取日历视图的实例(通过FindViewById)并用数据填充它?您可以在onCreate中创建整个视图结构-所有子视图和所有内容。当视图显示在屏幕上时,会调用onMeasure和onLayout。如果视图组具有如何测量和/或布局子视图的规则,则在创建层次结构时无关紧要。我的自定义视图组具有子视图(视图组内部,未在布局文件中指定)需要实例化。因为onMeasure(显然)在onCreate退出(并呈现)后才调用,如果我在onMeasure中初始化childern对象,则不会在onCreate中为我实例化childern对象以填充数据。我已尝试使用onResume获得类似结果。您不应该在onMeasure中创建它们。该方法用于测量。请在onCreate中创建它们并将它们添加到组中。onMeasure方法应控制大小我不熟悉ViewTreeObserver类。谢谢。哦,“ViewTreeObserver”,就像在XML布局树中一样!很好,这可能就是我一直在寻找的(如果它起作用,我会给你荣誉)…mOverlayFrameLayout是哪个对象的成员(我猜是FrameLayout…)好吧,你给我指出了正确的方向,并引导我去,所以感谢你!类似的帖子:
    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;
        }
    }