【问题标题】:How to organize RecyclerView on Chat App with different types of messages?如何使用不同类型的消息在聊天应用上组织 RecyclerView?
【发布时间】:2018-12-18 04:02:25
【问题描述】:

我开发聊天应用程序,有不同类型的消息:简单的文本、图像、文件等。 也只有消息(其他,在屏幕左侧)和我的消息(在屏幕右侧)。

现在我对每种类型的消息都有不同的布局:

  • 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 所以应该有 2 种视图类型:MESSAGE、MY_MESSAGE?以及 2 个仅具有“消息云”布局的 ViewHolders。而且我应该在 ViewHolder 中填充“消息正文”布局,对吧?
  • 不是 2 ,你想要多少都可以
  • 您可以在 getItemViewType() 中登录不同的类型
  • 在我的情况下,我也有相同类型的消息选项,并使用 onBindViewHolder() 中的 switch case 处理,具有可见性显示和隐藏。是的,当您添加新的消息类型时,您需要在 onBindViewHolder 中再添加一个案例来完成它,这很困难

标签: android android-layout chat android-recyclerview


【解决方案1】:

在我的情况下,我也有相同类型的消息选项,需要根据发件人消息和收到的消息进行区分。我为 Sender 和 Receiver 添加了不同的布局,同时根据消息类型创建了它自己的视图持有者

每个 msg 都有不同的消息选项(文本、图像、视频、文件、音频等),我使用 onBindViewHolder() 中的 switch case 处理了可见性显示和隐藏。

我共有三个不同的 viewHolders。

YOU :您发送的消息(它应该始终显示在屏幕上)在您的情况下 MY_MESSAGE

Others :其他人发送的消息(它应该始终显示在屏幕左侧)在您的情况下 MESSAGE

TIMELINE:时间线消息,例如用户更改了聊天名称、删除了 so n so 用户等

这里,

@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 和其他 xml 布局都有分别合并 Text、Image、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 中再添加一个 case 来添加它。

希望它能给你一些启发来完成你的任务。

【讨论】:

  • 感谢您的回答和示例!这是我认为的选项之一。时间表很棒,我认为它也会实施。但我认为这是一个有点沉重的解决方案,因为我们不能忘记显示/隐藏视图,它可能会变慢。如果在 show 方法中膨胀任何所需的布局怎么办? MESSAGE / MY_MESSAGE 将是父级,具体的消息类型布局将是子级
  • OFFTOP:为什么你使用 Glide,而不是 Picasso?:)
  • 是的,同意。隐藏和显示有点困难,但 ASAIK 膨胀也具有相同类型的复杂性。没试过这种方式
  • 谢谢!现在你的答案是最合适的
  • 是的,我会尝试充气,如果它可以正常工作,我在这里发布
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多