Как организовать RecyclerView в приложении чата с разными типами сообщений?

Я разрабатываю приложение для чата, есть разные типы сообщений: простой текст, изображение, файл и т. д. Также есть только сообщение (другое, слева от экрана) и мое сообщение (справа от экрана).

Теперь у меня разные макеты для каждого типа сообщения:

  • item_message_simple

  • item_my_message_simple

  • item_message_image

  • item_my_message_image

  • item_message_file

  • item_my_message_file

Все эти типы определены в RecyclerView.Adapter, а в getItemViewType () есть много условий if-else.

Также можно отвечать и пересылать сообщения, которые имеют более сложную структуру. И если я захочу добавить новый тип сообщения, это будет катастрофа.

Так как это лучше организовать? Возможно, это должно быть все в одном макете и 2 типа: MESSAGE, MY_MESSAGE - и показать / скрыть части макета. Или 2 типа еще раз (MESSAGE, MY_MESSAGE) и раздуть требуемый вложенный макет в ViewHolder.

Пожалуйста, помогите!

Надувать разные макеты по мере необходимости.

DKV 18.12.2018 05:08

@DKV, поэтому должно быть 2 типа просмотра: MESSAGE, MY_MESSAGE? И 2 ViewHolder с макетами только «облака сообщений». И я должен раздувать макет «тела сообщения» внутри этого ViewHolder, верно?

LIFED 18.12.2018 05:12

не 2, ты можешь иметь столько, сколько хочешь

DKV 18.12.2018 05:14

вы можете иметь свой логин для другого типа в getItemViewType ()

DKV 18.12.2018 05:16

В моем случае у меня также есть тот же тип параметров сообщения и обрабатывается с помощью case switch в onBindViewHolder () с отображением и скрытием видимости. да, это сложно, когда вы добавляете новый тип сообщения, вам нужно добавить еще один случай в onBindViewHolder для его выполнения

King of Masses 18.12.2018 05:46
4
5
1 696
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Каждое сообщение имеет разные параметры сообщения (текст, изображение, видео, файл, аудио и т. д.), И я обрабатывал регистр переключателя в onBindViewHolder () с отображением и скрытием видимости.

У меня есть три разных viewHolder вместе.

ВЫ: сообщения, отправленные вами (всегда должно отображаться прямо на экране) В вашем случае МОЕ СООБЩЕНИЕ

Другое: сообщения, отправленные другими пользователями (всегда должно отображаться слева на экране). В вашем случае СООБЩЕНИЕ

СРОК ВРЕМЕНИ: сообщения на шкале времени, например, пользователь изменил имя чата, удалил, так что пользователь и т. д.

Так вот,

@Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        MyViewHolder viewHolder = null;
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());

        switch (viewType) {
            case YOU:
                View v1 = inflater.inflate(R.layout.chat_right_layout, parent, false);
                viewHolder = new MyViewHolder(v1, true);
                break;
            case OTHERS:
                View v2 = inflater.inflate(R.layout.chat_left_layout, parent, false);
                viewHolder = new MyViewHolder(v2, false);
                break;
            case TIMELINE:
                View v3 = inflater.inflate(R.layout.chat_timeline_layout, parent, false);
                viewHolder = new MyViewHolder(v3, false);
                break;
        }
        return viewHolder;
    }

Здесь у меня есть 3 разных файла xml для (сообщений YOU, Others и TimeLine) Каждый макет You и другие макеты xml имеют представления для включения текста, изображения и PDF соответственно.

@Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
        ChatModel model = mDataList.get(position);

        if (model.getMessageType() == 10) // timeline message {
            holder.mTvTimeLine.setText(DecodeUtil.decodeBase64(model.getMessageText())+" on "+date);
        }else{
            showTextAndMediaData(holder, model);
        }
    }

Вот логика, которую я написал для обработки различных типов сообщений Индивидуальные (текстовое изображение и т. д. Для вас и других).

 private void showTextAndMediaData(MyViewHolder myViewHolder, ChatModel model) {

        switch (model.getMessageType()) {
            case 1:   // Image Type
                myViewHolder.mTxtMsg.setVisibility(View.GONE);
                myViewHolder.chatImageView.setVisibility(View.VISIBLE);
                myViewHolder.videoLayout.setVisibility(View.GONE);
                myViewHolder.documentImageView.setVisibility(View.GONE);

                    Uri mInitialUri = Uri.parse(model.getMessageText());
                    try {
                        myViewHolder.chatImageView.setImageURI(mInitialUri);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                break;
            case 3:  // video type
                myViewHolder.mTxtMsg.setVisibility(View.GONE);
                myViewHolder.chatImageView.setVisibility(View.GONE);
                myViewHolder.videoLayout.setVisibility(View.VISIBLE);
                myViewHolder.documentImageView.setVisibility(View.GONE);

                    Glide.with(mContext).load(Headers.getUrlWithHeaders(mContext, model.getThumbnailURL()))
                            .placeholder(R.drawable.novideo)
                            .thumbnail(0.5f)
                            .crossFade()
                            .diskCacheStrategy(DiskCacheStrategy.ALL)
                            .into(myViewHolder.vedioImageView);
                } 
                break;
            case 4: 
            case 5:
            case 6:
            case 7:
            case 8:
            case 9:   // file type
                myViewHolder.mTxtMsg.setVisibility(View.GONE);
                myViewHolder.chatImageView.setVisibility(View.GONE);
                myViewHolder.videoLayout.setVisibility(View.GONE);
                myViewHolder.documentImageView.setVisibility(View.VISIBLE);

                switch (model.getMediaType()) {
                    case "doc":
                        myViewHolder.documentImageView.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.img_word_document));
                        break;
                    case "pdf":
                        myViewHolder.documentImageView.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.img_pdf));
                        break;
                    case "excel":
                        myViewHolder.documentImageView.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.img_excel));
                        break;
                    case "ppt":
                        myViewHolder.documentImageView.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.img_ppt));
                        break;
                    case "txt":
                        myViewHolder.documentImageView.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.img_txt));
                        break;
                    case "csv":
                        myViewHolder.documentImageView.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.img_csv));
                        break;
                    default:
                        myViewHolder.documentImageView.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.img_otherdoc));
                }
                break;
            default:  // text type
                myViewHolder.mTxtMsg.setVisibility(View.VISIBLE);
                myViewHolder.chatImageView.setVisibility(View.GONE);
                myViewHolder.videoLayout.setVisibility(View.GONE);
                myViewHolder.documentImageView.setVisibility(View.GONE);

                    try {
                        myViewHolder.mTxtMsg.setText(text);
                    } catch (Exception e) {
                        e.printStackTrace();
                        myViewHolder.mTxtMsg.setText(text);
                    }

        }
    }

Удалена некоторая логика кейсов, так как все они разного типа и обрабатываются одинаково. У меня также есть дополнительная логика для отправителя и получателя, которая также удалена в этом блоке. вы можете добавить в соответствии с вашими потребностями

да, это сложно, когда вы добавляете новый тип сообщения, вам нужно добавить еще один случай в onBindViewHolder, чтобы добавить его.

Надеюсь, это поможет вам выполнить вашу задачу.

Спасибо за ответ и примеры! Это один из вариантов, который я предполагал. График отличный, думаю, он тоже будет реализован. Но я думаю, что это немного тяжелое решение, потому что мы не должны забывать показывать / скрывать представления, и, возможно, это замедлится. Что, если раздуть любой требуемый макет внутри метода шоу? MESSAGE / MY_MESSAGE будет родительским, а макет конкретного типа сообщения будет дочерним

LIFED 18.12.2018 06:24

OFFTOP: почему вы используете Glide, а не Picasso? :)

LIFED 18.12.2018 06:27

Да согласен. Скрытие и отображение - это немного сложная часть, но надувание ASAIK также имеет тот же тип сложности. Не пробовал таким образом

King of Masses 18.12.2018 06:28

За Glide против Пикассо! прочтите это medium.com/@multidots/glide-vs-picasso-930eed42b81d

King of Masses 18.12.2018 06:30

Спасибо! А пока ваш ответ самый подходящий

LIFED 18.12.2018 06:34

Если вы попробуете использовать подход Inflate, опубликуйте свои ответы здесь, чтобы я проверил оба и изменил свою логику. Но на данный момент в моем случае он работает нормально, как и ожидалось!

King of Masses 18.12.2018 06:34

Да, я попробую накачать и если все будет нормально, я разместил здесь

LIFED 18.12.2018 06:36

эй, вы пробовали надувать макет, если да, пришлите решение !!!

nilesh prajapati 09.09.2020 14:15

Другие вопросы по теме