我正在尝试在 RecylcerView 中实现聊天应用类型布局。现在唯一的问题是,即使我设置了 View 的宽度来环绕文本。在 RecyclerView 中,有时小词占据整行,有时这个词很好。
绿色突出显示是预期行为,红色突出显示是意外行为。
这是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);
}
}
}
注意:我注意到当消息离开屏幕并向上滚动时,布局会发生变化。
答案 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"
来清除此视图的前一项/文本集之后的文本