【发布时间】:2019-07-06 02:31:08
【问题描述】:
我正在创建一个聊天应用程序并显示我正在使用回收器视图的消息。最新消息显示在底部。用户向上滚动以查看更多消息。
加载聊天屏幕时,视图不会从最底部开始,并且最新消息不可见。用户必须向下滚动几行才能看到最新消息。这是糟糕的用户界面,最新消息应该显示在屏幕的末尾/底部。
我正在使用setReverseLayout(true) 和setStackFromEnd(false),并且我在网上搜索过类似的问题,但没有成功。目前,我在延迟设置回收站视图后将滚动位置设置为 0,但这并不总是有效,而且很跳跃。
如果我正常设置recyclerview(不使用setReverseLayout 和setStackFromEnd),最新消息每次都完美地加载在顶部。
这是启动回收器视图的代码:
RecyclerView recyclerView = findViewById(R.id.recyclerViewMessageRoom);
adapter = new RA_MessageRoom(this, userFirebaseUid, messagesGroupedByDate, messageUsers);
recyclerView.setAdapter(adapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(false);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
// -- Workaround with delay - still doesn't completely work
new Handler().postDelayed(() -> {
recyclerView.scrollToPosition(0);
}, 200);
任何遇到过此问题并知道如何解决的人请分享!谢谢。
编辑(2019 年 7 月 6 日):
这是回收器适配器的代码。提醒一下,如果我删除反向布局设置,它工作得很好。
RA_MessageRoom:
public class RA_MessageRoom extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = "RA_MessageRoom";
private static final int TYPE_USER = 1;
private static final int TYPE_PARTICIPANT = 2;
private Context context;
private String userFirebaseUid;
private List<MessagesDateGrouper> messagesGroupedByDate;
private HashSet<MessagesUserModel> messageUsers;
public RA_MessageRoom(Context context, String userFirebaseUid, List<MessagesDateGrouper> messagesGroupedByDate, HashSet<MessagesUserModel> messageUsers) {
this.context = context;
this.userFirebaseUid = userFirebaseUid;
this.messagesGroupedByDate = messagesGroupedByDate;
this.messageUsers = messageUsers;
}
@Override
public int getItemViewType(int position) {
if (messagesGroupedByDate.get(position).getViewType() == MessagesDateGrouper.TYPE_CHAT) {
MessageChatItem message = (MessageChatItem) messagesGroupedByDate.get(position);
if (message.getMessages().getSenderFirebaseUid().equals(userFirebaseUid)) {
return TYPE_USER;
} else {
return TYPE_PARTICIPANT;
}
} else {
return messagesGroupedByDate.get(position).getViewType();
}
}
@Override
public int getItemCount() {
return messagesGroupedByDate != null ? messagesGroupedByDate.size() : 0;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final RecyclerView.ViewHolder holder;
View view;
switch (viewType) {
case MessagesDateGrouper.TYPE_DATE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_message_room_separator, parent, false);
holder = new MessageRoomDateVH(view);
break;
case TYPE_USER:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_message_room_user, parent, false);
holder = new MessageRoomUserVH(view);
break;
case TYPE_PARTICIPANT:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_message_room_participant, parent, false);;
holder = new MessageRoomParticipantVH(view);
break;
default:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_message_room_user, parent, false);;
holder = new MessageRoomUserVH(view);
break;
}
return holder;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder instanceof MessageRoomDateVH) {
MessageDateItem date = (MessageDateItem) messagesGroupedByDate.get(position);
((MessageRoomDateVH)holder).date.setText(date.getDate());
} else if (holder instanceof MessageRoomParticipantVH) {
MessageRoomParticipantVH view = (MessageRoomParticipantVH) holder;
MessageChatItem messageItem = (MessageChatItem) messagesGroupedByDate.get(position);
MessagesModel message = messageItem.getMessages();
view.name.setText(context.getString(R.string.unknown));
view.profileImage.setImageResource(R.drawable.default_profile_image_grey);
for (MessagesUserModel user: messageUsers) {
if (user.getFirebaseId().equals(message.getSenderFirebaseUid())) {
int fallbackImage;
if (user.getMerchant() == null || !user.getMerchant()) {
fallbackImage = R.drawable.default_profile_image_grey;
} else {
fallbackImage = R.drawable.store_profile;
}
GlideApp.with(context)
.load(user.getPhotoThumbUrl())
.placeholder(R.drawable.placeholder)
.fallback(fallbackImage)
.into(view.profileImage);
view.name.setText(user.getName());
break;
}
}
if (message.getImageUrl() != null && !message.getImageUrl().equals("") ) {
view.image.setVisibility(View.VISIBLE);
view.imageSpinner.setVisibility(View.VISIBLE);
view.chat.setVisibility(View.GONE);
view.image.setClipToOutline(true);
GlideApp.with(context)
.load(message.getImageUrl())
.placeholder(R.drawable.placeholder_message)
.fallback(R.drawable.placeholder_message)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
view.imageSpinner.setVisibility(View.GONE);
return false;
}
})
.into(view.image);
} else {
view.chat.setVisibility(View.VISIBLE);
view.image.setVisibility(View.GONE);
view.imageSpinner.setVisibility(View.GONE);
view.chat.setText(message.getMessageText());
}
String time = DateFormatService.messageRoomParseDateToTimeString(message.getDate());
view.date.setText(time);
} else if (holder instanceof MessageRoomUserVH){
MessageRoomUserVH view = (MessageRoomUserVH) holder;
MessageChatItem messageItem = (MessageChatItem) messagesGroupedByDate.get(position);
MessagesModel message = messageItem.getMessages();
if (message.getImageUrl() != null && !message.getImageUrl().equals("") ) {
view.image.setVisibility(View.VISIBLE);
view.imageSpinner.setVisibility(View.VISIBLE);
view.chat.setVisibility(View.GONE);
view.image.setClipToOutline(true);
GlideApp.with(context)
.load(message.getImageUrl())
.placeholder(R.drawable.placeholder_message)
.fallback(R.drawable.placeholder_message)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
view.imageSpinner.setVisibility(View.GONE);
return false;
}
})
.into(view.image);
} else {
view.chat.setVisibility(View.VISIBLE);
view.image.setVisibility(View.GONE);
view.imageSpinner.setVisibility(View.GONE);
view.chat.setText(message.getMessageText());
}
String time = DateFormatService.messageRoomParseDateToTimeString(message.getDate());
view.date.setText(time);
}
}
public class MessageRoomDateVH extends RecyclerView.ViewHolder {
TextView date;
public MessageRoomDateVH(@NonNull View itemView) {
super(itemView);
date = itemView.findViewById(R.id.textMessageRoomDateSection);
}
}
public class MessageRoomParticipantVH extends RecyclerView.ViewHolder {
ImageView profileImage;
TextView name;
TextView chat;
ImageView image;
TextView date;
ProgressBar imageSpinner;
public MessageRoomParticipantVH(@NonNull View itemView) {
super(itemView);
profileImage = itemView.findViewById(R.id.imageMessageRoomParticipantProfile);
name = itemView.findViewById(R.id.textMessageRoomParticipantName);
chat = itemView.findViewById(R.id.textMessageRoomParticipantChat);
image = itemView.findViewById(R.id.imageMessageRoomParticipantImage);
date = itemView.findViewById(R.id.textMessageRoomParticipantDate);
imageSpinner = itemView.findViewById(R.id.progressBarMessageRoomParticipantImage);
}
}
public class MessageRoomUserVH extends RecyclerView.ViewHolder {
TextView chat;
ImageView image;
TextView date;
ProgressBar imageSpinner;
public MessageRoomUserVH(@NonNull View itemView) {
super(itemView);
chat = itemView.findViewById(R.id.textMessageRoomUserChat);
image = itemView.findViewById(R.id.imageMessageRoomUserImage);
date = itemView.findViewById(R.id.textMessageRoomUserDate);
imageSpinner = itemView.findViewById(R.id.progressBarMessageRoomUserImage);
}
}
}
编辑:
虽然首选是将 stackFromEnd 设置为 false,但我最终将 stackFromEnd 从 false 更改为 true,消除了延迟,并按照接受的答案的建议继续设置滚动位置以解决此问题。
更新的工作代码:
RecyclerView recyclerView = findViewById(R.id.recyclerViewMessageRoom);
adapter = new RA_MessageRoom(this, userFirebaseUid, messagesGroupedByDate, messageUsers);
recyclerView.setAdapter(adapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.scrollToPosition(0);
感谢您的帮助!
您还需要处理首页加载时的消息加载以及收到的新消息位于 recyclerview 底部:
if (pageLoad) {
list.add(Model)
} else {
// Add to the top of the list (since list is reverse message will come at the bottom)
list.add(0, Model)
}
【问题讨论】:
-
你能显示你的适配器代码吗?问题可能是其他问题,因为上面的代码看起来不错
-
使用 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, true); recyclerView.scrollToPosition(adapter.getItemCount() - 1);
-
@SyedAhmedJamil 我已经添加了适配器代码。如果您有任何想法,将不胜感激。
-
@sajadzohrei 我尝试按照您的方式设置 LinearLayoutManager,但问题仍然存在。
标签: android android-recyclerview