2011-06-09 59 views
9

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

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

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

演示此问题的简单示例是向ViewLayout添加/删除视图,并观察onMeasure被调用,尽管它不影响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,然后每一个您添加的时间/删除点击按钮查看视图。这显然运行良好,但你可以看到,当你有一个复杂的嵌套视图布局可能会有问题的地方不断调用onMeasure。

是否有推荐的方法来绕过这些onMeasure调用或至少onMeasure调用measureChildren?

+1

回答android-developers:http://groups.google.com/group/android-developers/browse_frm/thread/5951029333032455 – CommonsWare 2011-06-09 22:54:02

+0

感谢马克的交叉链接。我用我的更快/更脏的解决方案更新了原始帖子。 – 2011-06-10 15:47:38

+1

你能以一种可以帮助别人的方式回答你自己的问题吗?只需从您的问题中编辑出“解决方案”,并将其添加为新答案。一旦你这样做,你可以选择你的正确答案。这看起来很奇怪,但它是处理这种情况的首选方式。 – Will 2011-07-15 15:35:35

回答

0

而是我自己的滚动布局管理器(我仍然可以做在未来)的,我改变了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的硬编码的高度和宽度容器作为变量。将这些设置为您所期望的不在本解决方案的范围内。

int staticContainerHeight = 300; 
int staticContainerWidth = 300; 
+0

它不适合我,整个视图甚至不显示。 :/ – 2012-03-28 14:36:23

+0

使用scrollView作为父视图和setFillViewport(true)..应该工作! – AJit 2013-08-12 09:19:01

0

当动画发生在viewgroup的大小上时,我遇到了类似的问题,它的onMeasure()被非常频繁地调用。由于父视图包含许多子视图,频繁级联的onMeasure()调用导致动画性能呃逆。我有另一个肮脏的解决方案,但比推出我自己的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; 
    ... 
0

我也遇到了类似的问题,我的解决办法是检查尺寸发生改变:

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

mClientWidth = parentWidth; 
mClientHeight = parentHeight; 

所以,如果父母的尺寸没有真正改变,它不会被级联下到它的孩子。

+2

如果您在初始测量后向该父母添加了一个孩子,新孩子是否会接受测量?似乎不会在这种情况下...或者我忽略了什么? – 2011-11-09 16:44:41

相关问题