Recyclerview обратная раскладка, начальная проблема положения прокрутки - PullRequest
0 голосов
/ 06 июля 2019

Я создаю приложение чата и для отображения сообщений использую представление переработчика. Самые новые сообщения отображаются внизу. Пользователь прокручивает страницу, чтобы увидеть больше сообщений.

Когда загружается экран чата, представление не начинается с самого низа, а самое новое сообщение не отображается. Пользователь должен прокрутить несколько строк вниз, чтобы увидеть самое новое сообщение. Это плохой интерфейс, и самое последнее сообщение должно быть видно в конце / нижней части экрана.

Я использую setReverseLayout(true) и setStackFromEnd(false), и я искал в Интернете похожие проблемы, но не повезло. На данный момент я устанавливаю позицию прокрутки на 0 сразу после настройки представления переработчика с задержкой, но это не всегда работает, и это нервно.

Если я настрою утилиту обычного просмотра (без использования 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);

Всем, кто сталкивался с этой проблемой и знает, как ее решить, поделитесь! Спасибо.

РЕДАКТИРОВАТЬ (6 ИЮЛЯ 2019):

Вот код адаптера утилизатора. В качестве напоминания, если я уберу настройки обратного макета, он отлично работает.

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);

Спасибо за помощь!

Ответы [ 2 ]

0 голосов
/ 06 июля 2019

это очень просто, нужно добавить только одну строку: -

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(linearLayoutManager);
0 голосов
/ 06 июля 2019

См. Этот ответ:

RecyclerView - обратный порядок

И создайте установщик для RA_MessageRoom, чтобы обновить messagesGroupedByDate,Примерно так:

Collections.reverse(messagesGroupedByDate); // Reverse your dataset like in answer above
adapter.setMessagesGroupedByDate(messagesGroupedByDate); // Update your dataset in adapter
adapter.notifyDataSetChanged(); // Notify your adapter

При этом каждый раз, когда приходят новые сообщения, ваш список будет обновляться.Вам нужно поместить этот фрагмент в выборку данных, а затем удалить свой обработчик postDelayed.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...