RecyclerView 中的布局行为怪异

时间:2021-03-26 13:06:03

标签: android

我正在尝试在 RecylcerView 中实现聊天应用类型布局。现在唯一的问题是,即使我设置了 View 的宽度来环绕文本。在 RecyclerView 中,有时小词占据整行,有时这个词很好。

enter image description here

绿色突出显示是预期行为,红色突出显示是意外行为。

这是cardView的代码

<androidx.cardview.widget.CardView
    android:id="@+id/cardView3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginEnd="12dp"
    app:cardBackgroundColor="#00BCD4"
    app:cardCornerRadius="12dp"
    app:cardPreventCornerOverlap="false"
    app:cardUseCompatPadding="true"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.123">


    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/textMessageSent"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:maxWidth="260dp"
            android:paddingBottom="8dp"
            android:paddingLeft="12dp"
            android:paddingRight="12dp"
            android:paddingTop="8dp"
            android:text="oh noo"
            android:textColor="#000000"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:maxLines="10" />
    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>

这是适配器代码

public class ChatAdapter extends ListAdapter {

    String reciever,sender;

    public ChatAdapter(String from,String to)
    {
        super(DIFF_CALLBACK);
        this.reciever = from;
        this.sender = to;
    }

    private static final DiffUtil.ItemCallback<Chat> DIFF_CALLBACK = new DiffUtil.ItemCallback<Chat>() {
        @Override
        public boolean areItemsTheSame(@NonNull Chat oldItem, @NonNull Chat newItem) {
            return oldItem.getId() == newItem.getId();
        }

        @Override
        public boolean areContentsTheSame(@NonNull Chat oldItem, @NonNull Chat newItem) {
            return oldItem.getSender().equals(newItem.getSender()) &&
                    oldItem.getReciever().equals(newItem.getReciever()) &&
                    oldItem.getDate().equals(newItem.getDate()) &&
                    oldItem.getMessageIdSent() == newItem.getMessageIdSent() &&
                    oldItem.getMessageRecieved().equals(newItem.getMessageRecieved()) &&
                    oldItem.getTime().equals(newItem.getTime());
        }
    };

    private final int TEXT_MESSAGE_SENT = 0;
    private final int TEXT_MESSAGE_RECIEVED = 1;

    @Override
    public int getItemViewType(int position) {
        Chat currentChats = (Chat) getItem(position);
        if(!currentChats.getMessageRecieved().equals(""))
        {
            return TEXT_MESSAGE_RECIEVED;
        }
        else if(!currentChats.getMessageSent().equals(""))
        {
            return TEXT_MESSAGE_SENT;
        }
        return -1;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        View view;
        if(viewType == TEXT_MESSAGE_SENT)
        {
            view = layoutInflater.inflate(R.layout.me_text_message,parent,false);
            return new TextChatSenderViewHolder(view);
        }
        //if reciever is text
        view = layoutInflater.inflate(R.layout.other_text_message,parent,false);
        return new TextChatRecieverViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        Chat currentChat = (Chat) getItem(position);
        switch (holder.getItemViewType())
        {
            case TEXT_MESSAGE_RECIEVED:
                //bind REcievedText viewholder
                TextChatRecieverViewHolder viewHolder = (TextChatRecieverViewHolder) holder;
                if(!currentChat.getMessageRecieved().equals(""))
                {
                    viewHolder.textMessageRecieved.setText(currentChat.getMessageRecieved());
                    viewHolder.textTimeMessageRecieved.setText(currentChat.getTime());
                }
                break;
            case TEXT_MESSAGE_SENT:
                TextChatSenderViewHolder viewHolder2 = (TextChatSenderViewHolder) holder;
                if(!currentChat.getMessageSent().equals("")) {
                    viewHolder2.textMessageSent.setText(currentChat.getMessageSent());
                    viewHolder2.textTimeMessageSent.setText(currentChat.getTime());
                }
                break;


        }
    }

    class TextChatSenderViewHolder extends RecyclerView.ViewHolder
    {
        TextView textMessageSent,textTimeMessageSent;
        public TextChatSenderViewHolder(@NonNull View itemView) {
            super(itemView);
            textTimeMessageSent = itemView.findViewById(R.id.textTimeMessageSent);
            textMessageSent = itemView.findViewById(R.id.textMessageSent);
        }
    }

    class TextChatRecieverViewHolder extends RecyclerView.ViewHolder
    {
        TextView textMessageRecieved,textTimeMessageRecieved;
        public TextChatRecieverViewHolder(@NonNull View itemView) {
            super(itemView);
            textTimeMessageRecieved = itemView.findViewById(R.id.textTimeMessageRecieved);
            textMessageRecieved = itemView.findViewById(R.id.textMessageRecieved);
        }
    }

}

注意:我注意到当消息离开屏幕并向上滚动时,布局会发生变化。

2 个答案:

答案 0 :(得分:1)

您需要更改您的 onCreateViewHolder,在 else 中保留以下几行

    view = layoutInflater.inflate(R.layout.other_text_message,parent,false);
    return new TextChatRecieverViewHolder(view);

同时保持布局宽度为

wrap_content 

而不是

match_parent.
        

答案 1 :(得分:1)

通过覆盖 ListView 方法并让此方法返回 {{1 }}。这不是任何视图类型,但 getItemViewType 必须返回 -1,因此您将返回 onCreateViewHolder。如果任何消息的长度为 0,则此空布局将显示在列表中

另一个与错误回收实现相关的问题是您并不总是在 ViewHolder 内调用 R.layout.other_text_message,因为不一致的视图类型和 setText 检查(可能是不必要的,因为 {{1} } 然后是 onBindViewHolder)。当您了解回收的工作原理(上面链接)时,您会注意到,当您不总是在 if 中调用 itemType 时,回收的项目可能包含来自上一次迭代(滚动前)的文本,并且此重复文本将显示在此 -1(错误的回收者视图)

现在你的列表项视图有 setText ,它可能在回收前“记住”长度,在回收后显示设置,这里有些东西搞砸了。如果您想要文本换行,那么 onBindViewHolder 应该设置 position。将 android:layout_width="match_parent" (TextView) 保存在 android:layout_width="wrap_content" parent (android:layout_width="match_parent") 中效率非常低,可能会导致多次重绘/重新测量,parent 可能也应该有 ContraintLayout

我对您的建议是在将它们设置为适配器之前摆脱空消息 - 绘图机制不是过滤不适合绘制的不适当项目(在您的情况下为空消息)的地方。始终返回一些已知的视图类型并始终完全处理它(android:layout_width="wrap_content"CardView 方法),至少使用 android:layout_width="match_parent" 来清除此视图的前一项/文本集之后的文本

相关问题