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 完成,但出于依赖性原因,我会将其重构为以下内容:

  1. 从您正在使用的布局中拉出 child 视图 ChatBox 并将它们移动到自己的布局中。

  2. 使 ChatBox 扩充该布局并将视图添加到自身。 (使用 this 作为 inflate() 的第二个根视图参数。)

  3. 之后你可以在你的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);
}