简体   繁体   English

Android View实例化订单

[英]Android View Instantiation Order

EDIT: I was missing a key concept, the message queue, while creating my custom view and trying to update the view without using it turned out being the source of the issue I was having. 编辑:我错过了一个关键概念,消息队列,同时创建我的自定义视图并尝试更新视图而不使用它原来是我遇到的问题的根源。 This gets cleared up here: 这在这里被清除:

Android: Writing Custom Views that Support The Message Queue Android:编写支持Message Queue的自定义视图

It turns out that you need to let the runtime/android call OnMeasure after OnCreate exits ("like normal"), and in the mean time put any updates to the view in the message queue via the .post method. 事实证明,你需要让运行时/ android在OnCreate退出后调用OnMeasure(“正常”),并且同时通过.post方法将任何更新放到消息队列中。

So, you can grab a handle to the view, via FindViewById, in OnCreate as usual, and then post any updates to it (either through overrides like setText, or your own set functions) within a runnable (see above link). 因此,您可以像往常一样在OnCreate中通过FindViewById获取视图的句柄,然后在runnable中发布任何更新(通过setText或您自己的set函数覆盖)(参见上面的链接)。


I've been working on a custom view in android for quite some time now and have throughly experimented with constructors, attributes, layout parameters, and drawing methods (OnMeasure, OnLayout, ...). 我已经在android中开发了一个自定义视图已经有一段时间了,并且已经完成了构造函数,属性,布局参数和绘图方法(OnMeasure,OnLayout,...)的实验。

The parent-most viewgroup (the one declared in the layout file for rendering) inherits from RelativeLayout and contains three child views, all custom/inherited viewgroups as well, and so on. 最父视图组(在布局文件中声明用于渲染的视图组)继承自RelativeLayout并包含三个子视图,所有自定义/继承的视图组也是如此,依此类推。

I'm implementing a custom calendar (I know, very original and exciting), I'll call CustomCalendar. 我正在实现一个自定义日历(我知道,非常原创和令人兴奋),我将调用CustomCalendar。 So, in my layout file I have the statment 所以,在我的布局文件中,我有这个声明

<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"
 ...
/>

This view resides along side a few others that are defined in the layout file as well, and thus the source of my complication, which will be stated now. 此视图与布局文件中定义的其他一些视图一起存在,因此也是我的复杂功能的来源,现在将说明。

I'm trying to figure out how to get this view's dimensions before OnMeasure is called (where I can get them no problem, however because the layout dimensions of the children views are determined from this views dimensions, I cannot instantiate the childeren views until the first time OnMeasure is called, and this proves to be after I need it; after OnCreate exits). 我试图弄清楚如何在OnMeasure被调用之前得到这个视图的尺寸(我可以在那里得到它们没有问题,但是因为子视图的布局尺寸是从这个视图尺寸确定的,所以我无法实例化孩子的视图直到第一次调用OnMeasure,这证明是在我需要它之后;在OnCreate退出之后)。

That is, after calling SetContentView in OnCreate, and then instantiating the custom view from it via FindViewById(Resource.Id.Calendar1), the child views do not get instantiated as well if its done from the OnMeasure override (again, b/c OnMeasure isn't called until after OnCreate returns). 也就是说,在OnCreate中调用SetContentView,然后通过FindViewById(Resource.Id.Calendar1)从中实例化自定义视图后,如果从OnMeasure覆盖完成,则子视图也不会被实例化(再次,b / c OnMeasure)直到OnCreate返回后才调用)。

If I read the attributes passed into the constructor, alls I get from layout_width and layout_height are the constant -1 for fill_parent. 如果我读取传递给构造函数的属性,那么我从layout_width和layout_height获得的所有内容都是fill_parent的常量-1。 I cannot just use the entire screen either, because there are other views to compensate for. 我也不能只使用整个屏幕,因为还有其他视图可以补偿。


Therefore, I'm looking for the best approach in determining the dimensions of a custom view from within its constructor so that I can instantiate all of the view's childern from it (the constructor) with the proper layout dimensions so that the views are available from OnCreate (for updating with content) after SetContentView is called and before returning from OnCreate. 因此,我正在寻找从其构造函数中确定自定义视图的维度的最佳方法,以便我可以使用适当的布局维度从它(构造函数)实例化所有视图的childern,以便可以从调用SetContentView之后和从OnCreate返回之前的OnCreate(用于更新内容)。

Another means to the same end will be fine with me, though I'm kinda looking to do this the way the infrastructure intends it to be (if there is such a thing). 对于同一目的的另一种方法对我来说没问题,尽管我有点想要按照基础设施的意图去做(如果有这样的事情)。

You can't get dimensions in the constructor. 您无法在构造函数中获取维度。 At best, if they are defined in XML, you could get the layout width and height from the AttributeSet. 最好的情况是,如果它们是用XML定义的,您可以从AttributeSet获取布局宽度和高度。

What you should be doing is overriding onMeasure and onLayout. 你应该做的是压倒onMeasure和onLayout。 You can do whatever calculations and setup you need in onMeasure, then pass the calculated values to measureChild(view, widthSpec, heightSpec) . 您可以在onMeasure中执行所需的任何计算和设置,然后将计算值传递给measureChild(view, widthSpec, heightSpec) and you can mess with layout stuff in onLayout then call childView.layout(left, top, right, bottom) . 你可以搞乱onLayout中的布局内容然后调用childView.layout(left, top, right, bottom)

I think I had this problem. 我想我有这个问题。 I'm not sure of the timing myself, but I did the following to get the dimensions 我不确定自己的时间,但我做了以下工作以获得尺寸

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

EDIT Dont do this (see OP's edit note). 编辑不要这样做(参见OP的编辑说明)。


It ends up being that onMeasure is where this problem is solved... 它最终是onMeasure是解决这个问题的地方......

Ya just got to call Measure on the view from OnCreate, which requires constructing the width and height MeasureSpec parameters that Measure uses: 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);

        ...
    }
}

Then just recursively do the same for all nested/child views. 然后只是递归地对所有嵌套/子视图执行相同的操作。

I have a static bool variable in each custom view that keeps track if the view has been initialized, and check it in onMeasure to determine if I should initialize and measure them. 我在每个自定义视图中都有一个静态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