正确实现自定义视图和动态添加子级

时间:2015-06-11 08:19:19

标签: android android-layout android-custom-view horizontalscrollview

我正在扩展Horizo​​ntalScrollView。调用公共setItems方法时,此布局会将子项添加到LinearLayout。这些子视图动态膨胀,其宽度取决于父级(仅在一个视图时填充父级,在> = 2个项目时为1/2父级)。

<!-- custom_layout.xml -->
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:id="@+id/container"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="match_parent">
    </LinearLayout>
</merge>

有时,在网络请求的回调中调用setItems,因此布局可能已经完全膨胀。我应该在哪里调用需要父母宽度的updateView并添加膨胀的孩子?我将调用放在onSizeChangedsetItems中,如下所示。

public class CustomLayout extends HorizontalScrollView {

    private LinearLayout container; 
    private List<Item> items;

    public void setItems(List<Item> items) {
        this.items = items;
        updateView();
    }

    public CustomLayout(Context context) {
        super(context);
        init();
    }

    public CustomLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        View v = inflate(getContext(), R.layout.custom_layout, this);
        container = (LinearLayout) v.findViewById(R.id.container);
        updateView();
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        updateView();
    }

    public void updateView() {
        if (items == null) {
            return;
        }

        container.removeAllViews();

        int width = getWidth();
        if (items.size() > 1) {
            width = width * 1 / 2;
        }

        for (final Item item : items) {        
            View child = LayoutInflator.from(getContext(), R.layout.custom_item, container, false);                   
            child.setLayoutParams(new LinearLayout.LayoutParams(width, LinearLayout.LayoutParams.MATCH_PARENT));
            container.addView(child);
        }
    }

}

我不知道为什么这种方式并不总是有效。有时,孩子container由于某种原因无法呈现。查看布局层次结构显示Horizo​​ntalScrollView没有子项。 container发生了什么事?

此外,似乎即使在网络电话中,setItemsonSizeChanged之前被称为,这让我觉得onSizeChanged是错误的这个地方updateView

1 个答案:

答案 0 :(得分:0)

尝试将updateView()方法放在onMeasure内,而不是onSizeChanged,并使用getMeasuredWidth()代替getWidth()

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    updateView();
}

public void updateView() {
    if (items == null) {
        return;
    }

    container.removeAllViews();

    int width = getMeasuredWidth();
    if (items.size() > 1) {
        width = width * 1 / 2;
    }

    for (final Item item : items) {        
        View child = LayoutInflator.from(getContext(), R.layout.custom_item, container, false);                   
        child.setLayoutParams(new LinearLayout.LayoutParams(width, LinearLayout.LayoutParams.MATCH_PARENT));
        container.addView(child);
    }
}

此外,如果您从异步请求的回调中调用setItems()方法,请不要忘记使用runOnUiThread的{​​{1}}方法在UI线程上运行它。