自定义ViewGroup寻找子View

需要获取自定义ViewGroup下的任意层级的已知id的子View

首先在attrs中定义没有format的attr,例如:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ChatView">
        <attr name="chatview_ptr" />
        <attr name="chatview_msg_list" />
        <attr name="chatview_input" />
    </declare-styleable>
</resources>

然后在layout中添加子view,例如:

<imui.jiguang.cn.imuisample.views.ChatView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/chat_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#f3f3f3"
    android:orientation="vertical"
    app:chatview_input="@+id/chat_input"
    app:chatview_msg_list="@+id/msg_list"
   app:chatview_ptr="@+id/pull_to_refresh_layout">

{包含id为chat_input、msg_list、pull_to_refresh_layout的子view}
</imui.jiguang.cn.imuisample.views.ChatView>

然后在自定义ViewGroup的java文件中获取子View的id,例如:

private void init(Context context, AttributeSet attributeSet) {
    TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.ChatView);
    int UNSET = -1;

    resIdPtr = a.getResourceId(R.styleable.ChatView_chatview_ptr, UNSET);
    if (resIdPtr == UNSET) {
        resIdPtr = a.getInt(R.styleable.ChatView_chatview_ptr, UNSET);
    }
    resIdMsgList = a.getResourceId(R.styleable.ChatView_chatview_msg_list, UNSET);
    if (resIdMsgList == UNSET) {
        resIdMsgList = a.getInt(R.styleable.ChatView_chatview_msg_list, UNSET);
    }
    resChatInput = a.getResourceId(R.styleable.ChatView_chatview_input, UNSET);
    if (resChatInput == UNSET) {
        resChatInput = a.getInt(R.styleable.ChatView_chatview_input, UNSET);
    }

    a.recycle();
}

然后在onAttachedToWindow()中,通过子view 的id获取子view的对象。

有个问题是ViewGroup的onAttachedToWindow()调用的时机是在Activity的onResume,可能会导致多余的findViewById子View的初始化被调用,不是太优,所以可以将findViewById(int id)放到一个initView()方法中,再将initView()方法用public暴露出来,给Activity在onCreate中调用,而不在自身的onAttachedToWindow()中调用。

像ConstraintLayout这样需要寻找子一层的所有未知id的子View

可以参照ConstraintLayout的源码那样,定义一个列表存储子View的id

private SparseArray<View> mChildrenByIds = new SparseArray<>();

private void init(Context context, AttributeSet attributeSet) {
    mChildrenByIds.put(getId(), this);
}

@Override
public void setId(int id) {
    mChildrenByIds.remove(getId());
    super.setId(id);
    mChildrenByIds.put(getId(), this);
}

@Override
public void onViewAdded(View child) {
    super.onViewAdded(child);
    mChildrenByIds.put(child.getId(), child);
}

@Override
public void onViewRemoved(View child) {
    super.onViewRemoved(child);
    mChildrenByIds.remove(child.getId());
}

public View getViewById(int id) {
    return mChildrenByIds.get(id);
}

然后在onAttachedToWindow()中通过getViewById(int id)得到子View对象

Share

You may also like...

发表评论

电子邮件地址不会被公开。 必填项已用*标注