5

I develop chat app, there is different type of message: simple text, image, file, etc. Also there is just message (other, on the left of screen) and my message (on the right of screen).

Now I have different layout for every type of message:

  • item_message_simple

  • item_my_message_simple

  • item_message_image

  • item_my_message_image

  • item_message_file

  • item_my_message_file

All of these types are defined in RecyclerView.Adapter and there is many if-else conditions in getItemViewType()

Also messages may be replied and forwarded which has more complicated layouts. And if I want to add new message type it will be disaster.

So how to organize it better way? Maybe it should be all in one layout and 2 types: MESSAGE, MY_MESSAGE - and show/hide parts of layout. Or 2 types again (MESSAGE, MY_MESSAGE) and inflate required sub-layout in ViewHolder.

Please any help!

LIFED
  • 467
  • 1
  • 4
  • 16
  • Inflater different layout as you need. – DKV Dec 18 '18 at 04:08
  • @DKV so there should be 2 viewTypes: MESSAGE, MY_MESSAGE? And 2 ViewHolders with just "message cloud" layouts. And I should inflate "message body" layout inside that ViewHolder, right? – LIFED Dec 18 '18 at 04:12
  • not 2 , you can have as much as u want – DKV Dec 18 '18 at 04:14
  • you can have your login for different type in getItemViewType() – DKV Dec 18 '18 at 04:16
  • In my case also i have the same type of message options and handled with switch case in onBindViewHolder() with visibility show and hide. yes it's difficult when u add a new message type u need to add one more case in onBindViewHolder to accomplish it – King of Masses Dec 18 '18 at 04:46

1 Answers1

5

In my case also i have the same type of message options and need to differentiate based on the Sender messages and Received messages. I added the different layouts for Sender and Receiver while creating the view holder it self based on the message type

Each msg having different message options ( Text, Image, Video , File , Audio, etc) and I handled with switch case in onBindViewHolder() with visibility show and hide.

I have three different viewHolders all together.

YOU : Messages sent by You (It should show always right in the screen) In your case MY_MESSAGE

Others : Messages sent by Others (It should show always left in the screen) In your case MESSAGE

TIMELINE: Timeline messages like user changed the chat name, removed so n so user etc

So here,

@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;
    }

Here i have 3 different xml files all together for (YOU, Others and TimeLine messages) Each You and other xml layouts have the views to incorporate the Text , Image, PDF respectively.

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

Here is the logic I wrote to handle the different message types Individual (Text Image etc for You and Others).

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

        }
    }

Removed some case logic's as all are different type and handled in the same manner. I also have some more logic for sender and receiver that also removed in this block. you can add as per your needs

yes it's difficult when u add a new message type u need to add one more case in onBindViewHolder to add it.

Hope it will give some heads up to you to accomplish your task.

King of Masses
  • 18,405
  • 4
  • 60
  • 77
  • Thank you for answer and examples! This is one of options that I supposed. Timeline is great, I think it will be implemented too. But I think it's a bit heavy solution because we must not to forget show / hide views and it maybe is gets slow down. What if to inflate any required layout inside show method? MESSAGE / MY_MESSAGE will be parent, and concrete message type layout will be child – LIFED Dec 18 '18 at 05:24
  • OFFTOP: why you use Glide, not the Picasso?:) – LIFED Dec 18 '18 at 05:27
  • Yes agree. hiding and showing is bit hard part but ASAIK inflating also have the same type of complexity. Not tried in that way – King of Masses Dec 18 '18 at 05:28
  • For Glide vs Picasso ! read this https://medium.com/@multidots/glide-vs-picasso-930eed42b81d – King of Masses Dec 18 '18 at 05:30
  • 1
    Thanks! For now your answer is the most suitable – LIFED Dec 18 '18 at 05:34
  • If you try vth the Inflate approach, post your answers here, so that vll check both and change my logics. But as of now in my case it is working fine as expected ! – King of Masses Dec 18 '18 at 05:34
  • 1
    Yes, I'll try inflating and if it will work fine I posted here – LIFED Dec 18 '18 at 05:36
  • hey have you tried inflating layout if yest Please send solution!!! – nilesh prajapati Sep 09 '20 at 12:15