Android View实例化订单

时间:2012-10-16 20:59:17

标签: c# android mobile xamarin.android

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

Android: Writing Custom Views that Support The Message Queue

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

所以,你可以像往常一样通过OnCreate中的FindViewById抓取视图的句柄,然后 发布任何更新(通过像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之前获取此视图的尺寸(在那里我可以得到它们没问题,但是因为子视图的布局尺寸是从这个视图尺寸确定的,所以我不能实例化childeren在第一次调用OnMeasure之前的观点,这证明是在我需要它之后;在OnCreate退出之后。)

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

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


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

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

3 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

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


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

Ya只需要在OnCreate的视图上调用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;
        }
    }