将视图添加到ViewGroup时,可以跳过onMeasure?

回答

我有一个RelativeLayout,在用户垂直或水平滚动时dynamic添加视图。 我已经推出了自己的ViewRecycler,因为可能有成千上万的视图可以组成整个可以滚动的视图,但是我只能在任何时候显示30个左右。 想象一个放大的日历视图。

当我添加即将看到的视图时,我遇到了性能问题,在RelativeLayout级联到onMeasure上调用onMeasure,并在其所有子视图上调用onMeasure。 我已经有了RelativeLayout有多大的计算大小,并且已经在LayoutParameters上设置了它,所以不需要测量ViewGroup,也不需要重新测量已经添加了最终大小和新增的视图增加的观点对这些观点没有影响。

演示这个问题的简单例子是添加/删除一个View到一个RelativeLayout,并观察onMeasure被调用,尽pipe它不影响RelativeLayout的大小或其他视图的位置。

main.xml中

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/shell" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content"> </LinearLayout> 

    MyActivity.java

     public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ViewGroup shell = (ViewGroup) findViewById(R.id.shell); final RelativeLayout container = new RelativeLayout(this) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); Log.d("MyActvity", "onMeasure called on map"); } }; container.setBackgroundColor(Color.rgb(255, 0, 0)); ViewGroup.LayoutParams containerParams = new ViewGroup.LayoutParams(300, 300); final TextView childView = new TextView(this); childView.setBackgroundColor(Color.rgb(0, 255, 0)); childView.setText("Child View"); Button viewToggle = (Button) findViewById(R.id.button); viewToggle.setText("Add/Remove Child View"); viewToggle.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { if (childView.getParent() == null) { container.addView(childView, 400, 30); } else { container.removeView(childView); } } }); shell.addView(container, containerParams); } } 

    运行这个程序,你会看到2个初始(预期)的onMeasure调用,然后每次你通过点击button添加/删除视图。 这显然运行良好,但你可以看到,当你有一个复杂的嵌套视图布局可能会有问题的地方不断调用onMeasure。

    有没有build议的方式来绕过这些onMeasure电话或至lessonMeasure调用measureChildren?

    Related of "将视图添加到ViewGroup时,可以跳过onMeasure?"

    而不是滚动我自己的布局pipe理器(我将来可能还会这样做),我将onMeasure更改为:

     @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount(); for (int i = 0; count > i; i++) { View v = getChildAt(i); if (v.getVisibility() != GONE) { if (v.getMeasuredWidth() <= 0 || v.getMeasuredHeight() <= 0) { measureChild(v, MeasureSpec.makeMeasureSpec(v.getLayoutParams().width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(v.getLayoutParams().height, MeasureSpec.AT_MOST)); } } } setMeasuredDimension(resolveSize(staticContainerWidth, widthMeasureSpec), resolveSize(staticContainerHeight, heightMeasureSpec)); } 

    …并为容器添加一个sudo-hard编码的高度和宽度作为variables。 将这些设置为您所期望的不在本解决scheme的范围之内。

     int staticContainerHeight = 300; int staticContainerWidth = 300; 

    当animation发生在视图组的大小上时,我碰到了一个类似的问题,它的onMeasure()被非常频繁地调用。 由于父视图包含许多子视图,频繁级联的onMeasure()调用导致animation性能呃逆。 我有另一个肮脏的解决scheme,但比推出我自己的layoutManager更简单。

     long mLastOnMeasurTimestamp; ... @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ... long currentTimestamp = System.currentTimeMillis(); if(currentTimestamp - mLastOnMeasureTimestamp < SKIP_PERIOD_IN_MILL){ return; } mLastOnMeasureTimestamp = currentTimestamp; ... 

    我遇到了类似的问题,我的解决scheme是检查尺寸是否已经改变:

     int parentWidth = MeasureSpec.getSize(widthMeasureSpec); int parentHeight = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(parentWidth, parentHeight); if ( mClientWidth == parentWidth && mClientHeight == parentHeight ) { return; } mClientWidth = parentWidth; mClientHeight = parentHeight; 

    所以,如果家长的维度没有真正改变,那么这个维度就不会被层层递进。