findviewbyid - 具有嵌套视图的自定义视图
findviewbyid - custom view with nested views
我有以下代码,我的问题是 findviewbyid 返回 null。
<es.ric.firebase.chat.core.views.chatbox.ChatBox
android:id="@+id/chatbox"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<LinearLayout
android:id="@+id/ll_text"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<EditText
android:id="@+id/messageEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_gravity="center_vertical"
android:paddingLeft="15dp"
android:hint="Escribir mensaje"
android:background="@drawable/background_chat"/>
<ImageButton
android:id="@+id/bt_upload_picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_insert_photo_black_24dp"
android:background="@android:color/transparent"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:layout_marginRight="10dp"/>
</RelativeLayout>
<ImageButton
android:id="@+id/sendButton"
android:layout_width="36dp"
android:layout_height="36dp"
android:src="@drawable/ic_send_white_24dp"
android:background="@drawable/background_circle"
android:layout_gravity="bottom"/>
</LinearLayout>
</es.ric.firebase.chat.core.views.chatbox.ChatBox>
Java class.
public class ChatBox extends LinearLayout {
enum State { MODE_MESSAGE, MODE_AUDIO, MODE_RECORDING }
private EditText messageEditText;
private ImageButton bt_upload_picture;
private ImageButton sendButton;
private WeakReference<ChatBoxListener> weak_listener;
private State state;
public ChatBox(Context context) {
super(context);
init();
}
public ChatBox(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ChatBox(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ChatBox(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init(){
messageEditText = findViewById(R.id.messageEditText);
bt_upload_picture = findViewById(R.id.bt_upload_picture);
sendButton = findViewById(R.id.sendButton);
}
}
调用onFinishInflate
方法后可以访问子视图:
@Override
protected void onFinishInflate() {
init();
}
当您的自定义视图构造函数运行并调用 init()
时,child 视图尚未实例化,也未添加到您的 ChatBox
布局中。
在同一布局中声明从视图组到特定 children 的依赖关系无论如何都不是一个好主意。 ChatBox
和它的使用位置之间存在不必要的耦合。
您可以等待 inflation 完成,但出于依赖性原因,我会将其重构为以下内容:
从您正在使用的布局中拉出 child 视图 ChatBox
并将它们移动到自己的布局中。
使 ChatBox
扩充该布局并将视图添加到自身。 (使用 this
作为 inflate()
的第二个根视图参数。)
之后你可以在你的ChatBox
里面找到children。
它找不到视图,因为您的视图还不存在。在您的 init 函数中,只有对象已经创建。
您需要提供一个 globalLayoutListener,它会在您的布局准备就绪时通知您。要执行此操作 ViewTreeObserver.OnGlobalLayoutListener
在你的初始化函数中附加监听器
private void init(){
this.getViewTreeObserver().addOnGlobalLayoutListener(this)
}
最后在onGlobalLayout中调用findViewById
@Override
public void onGlobalLayout(){
messageEditText = findViewById(R.id.messageEditText);
bt_upload_picture = findViewById(R.id.bt_upload_picture);
sendButton = findViewById(R.id.sendButton);
}
我有以下代码,我的问题是 findviewbyid 返回 null。
<es.ric.firebase.chat.core.views.chatbox.ChatBox
android:id="@+id/chatbox"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<LinearLayout
android:id="@+id/ll_text"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<EditText
android:id="@+id/messageEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_gravity="center_vertical"
android:paddingLeft="15dp"
android:hint="Escribir mensaje"
android:background="@drawable/background_chat"/>
<ImageButton
android:id="@+id/bt_upload_picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_insert_photo_black_24dp"
android:background="@android:color/transparent"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:layout_marginRight="10dp"/>
</RelativeLayout>
<ImageButton
android:id="@+id/sendButton"
android:layout_width="36dp"
android:layout_height="36dp"
android:src="@drawable/ic_send_white_24dp"
android:background="@drawable/background_circle"
android:layout_gravity="bottom"/>
</LinearLayout>
</es.ric.firebase.chat.core.views.chatbox.ChatBox>
Java class.
public class ChatBox extends LinearLayout {
enum State { MODE_MESSAGE, MODE_AUDIO, MODE_RECORDING }
private EditText messageEditText;
private ImageButton bt_upload_picture;
private ImageButton sendButton;
private WeakReference<ChatBoxListener> weak_listener;
private State state;
public ChatBox(Context context) {
super(context);
init();
}
public ChatBox(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ChatBox(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ChatBox(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init(){
messageEditText = findViewById(R.id.messageEditText);
bt_upload_picture = findViewById(R.id.bt_upload_picture);
sendButton = findViewById(R.id.sendButton);
}
}
调用onFinishInflate
方法后可以访问子视图:
@Override
protected void onFinishInflate() {
init();
}
当您的自定义视图构造函数运行并调用 init()
时,child 视图尚未实例化,也未添加到您的 ChatBox
布局中。
在同一布局中声明从视图组到特定 children 的依赖关系无论如何都不是一个好主意。 ChatBox
和它的使用位置之间存在不必要的耦合。
您可以等待 inflation 完成,但出于依赖性原因,我会将其重构为以下内容:
从您正在使用的布局中拉出 child 视图
ChatBox
并将它们移动到自己的布局中。使
ChatBox
扩充该布局并将视图添加到自身。 (使用this
作为inflate()
的第二个根视图参数。)之后你可以在你的
ChatBox
里面找到children。
它找不到视图,因为您的视图还不存在。在您的 init 函数中,只有对象已经创建。
您需要提供一个 globalLayoutListener,它会在您的布局准备就绪时通知您。要执行此操作 ViewTreeObserver.OnGlobalLayoutListener
在你的初始化函数中附加监听器
private void init(){
this.getViewTreeObserver().addOnGlobalLayoutListener(this)
}
最后在onGlobalLayout中调用findViewById
@Override
public void onGlobalLayout(){
messageEditText = findViewById(R.id.messageEditText);
bt_upload_picture = findViewById(R.id.bt_upload_picture);
sendButton = findViewById(R.id.sendButton);
}