需要获取自定义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对象