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

Kel*_*ell 10 layout android viewgroup

回答

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

当我添加即将看到的视图时遇到性能问题,在RelativeLayout上调用onMeasure,级联到onMeasure,调用它的所有子视图.我已经计算了RelativeLayout有多大的计算大小,并在它的LayoutParameters上设置了它,因此测量ViewGroup不是必需的,也不是重新测量已经添加了最终大小的视图和新的添加的视图与这些视图无关.

演示问题的简单示例是向RelativeLayout添加/删除View并观察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>
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

运行此命令,您将看到对onMeasure的2个初始(预期)调用,然后每次通过单击按钮添加/删除视图时调用一个.这显然运行良好,但是当您具有嵌套视图的复杂布局时,您可以看到对onMeasure的常量调用可能会出现问题.

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

Kel*_*ell 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));
}
Run Code Online (Sandbox Code Playgroud)

...并添加了容器的 sudo 硬编码高度和宽度作为变量。将这些设置为您期望的值超出了此解决方案的范围。

int staticContainerHeight = 300;
int staticContainerWidth = 300;
Run Code Online (Sandbox Code Playgroud)