Recyclerview gives us the real power to use different types of child rows depending on our need. What I mean is there might be the situation when you need to use different layouts with respect to different data or depending on your need with different positions i.e heterogenous structure.
If you have not visited previous RecyclerView tutorial for homogeneous layout I strongly recommend you to visit that first.
Here we are going to see an example of chat screen in which there are two different child layouts used to meet the need to separate the messages of sender and receiver.
Here we are considering sender and receiver both on the same screens (lol), differentiated with just the buttons they are going to use to send the message.
Steps:
- Import gradle dependency for recyclerview and design support library in build.gradle(Module:app).
- Insert recyclerview in the layout where we want heterogeneous list, and add a footer layout to implement two buttons to send and receive messages and a shared space to write message.
- Make two different child row that will be inflated in recyclerview
- Add some colors in colors.xml
- Create some drawables.
- Create style for buttons in footer layout of activity_main in step two.
- Create a model class which will contain data for the recyclerview child.
- Code the recycleview adapter.
- Assign adapter to our recyclerview.
- Run and see the chatting with yourself ย ๐
As we start a new project we will have MainActivity.java and activity_main.xml without changing anything.
Step 1:
Open your build.gradle(Module: app) and add as following in dependencies:
After adding dependencies, the module looks like below
1 2 3 4 5 6 7 |
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.4.0' compile 'com.android.support:design:23.4.0' compile 'com.android.support:recyclerview-v7:23.4.0' } |
Step 2:
Now we need to insert recyclerview ย and footer layout in our activity_main.xml as shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/chat_screen_color" android:orientation="vertical"> <android.support.v7.widget.RecyclerView android:id="@+id/chat_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@+id/footer" android:padding="10dp" /> <LinearLayout android:id="@+id/footer" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="@drawable/rounded_edittext" android:orientation="horizontal" android:layout_margin="5dp" android:weightSum="1.6"> <Button android:id="@+id/receive_button" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="0.3" style="@style/ButtonsWidget" android:text="Receive" /> <EditText android:id="@+id/texttosend" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="3dp" android:layout_weight="1" android:background="@color/bg_edittext" android:hint="Enter message" android:inputType="textMultiLine" android:maxLines="4" android:padding="3dp" android:scrollHorizontally="false" /> <Button android:id="@+id/send_button" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="0.3" style="@style/ButtonsWidget" android:text="Send" /> </LinearLayout> </RelativeLayout> |
Step 3:
- Make two different child row that will be inflated in recyclerview
received_message.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="60dp" android:layout_marginRight="60dp" android:gravity="start" android:orientation="vertical"> <TextView android:id="@+id/message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/bg_received_message" android:padding="10dp" android:textColor="@color/bg_color_sent_msg" android:textSize="16sp" /> <TextView android:id="@+id/date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:textColor="@android:color/white" android:textSize="10sp" android:textStyle="italic" /> </LinearLayout> |
sent_message.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="60dp" android:layout_marginStart="60dp" android:gravity="end" android:orientation="vertical"> <TextView android:id="@+id/message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/bg_sent_message" android:padding="10dp" android:textColor="#FBFCFC" android:textSize="16sp" /> <TextView android:id="@+id/date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:textColor="@android:color/white" android:textSize="10sp" android:textStyle="italic" /> </LinearLayout> |
- Add some colors in colors.xml
1 2 3 4 5 6 7 8 9 10 11 |
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#34495E</color> <color name="colorPrimaryDark">#212F3D</color> <color name="colorAccent">#FF4081</color> <color name="bg_edittext">#5D6D7E</color> <color name="edittext_background">#F5F5F5</color> <color name="chat_screen_color">#34495E</color> <color name="bg_color_sent_msg">#FBFCFC</color> </resources> |
- Create some drawables.
bg_received_message
1 2 3 4 5 6 7 |
<?xml version="1.0" encoding="utf-8"?> <shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android" > <solid android:color="#3498DB"/> <corners android:radius="5dp"/> <stroke android:color="#E8DAEF" android:width="1dp"/> </shape> |
bg_sent_message
1 2 3 4 5 6 7 8 9 |
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#2E4053" /> <corners android:radius="5dp" /> <stroke android:width="1dp" android:color="#5D6D7E" /> </shape> |
rounded_edittext
1 2 3 4 5 6 7 |
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:padding="5dp" android:shape="rectangle"> <solid android:color="@color/bg_edittext" /> <corners android:radius="5dp" /> </shape> |
- Create style for buttons in footer layout in styles.xml.
1 2 3 4 |
<style name="ButtonsWidget" parent="Widget.AppCompat.Button"> <item name="android:background">@color/colorPrimaryDark</item> <item name="android:textColor">@android:color/white</item> </style> |
Step 4:
Create a model class which will contain data for the recyclerview child. Here we have created MessageModel.java that contains three variables message, isSender (Where message is from), time.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class MessageModel { private String message = null; private Boolean isSender = null; private String time = null; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getTime() { return time; } public void setTime(String time) { this.time = time; } public Boolean getSender() { return isSender; } public void setSender(Boolean sender) { isSender = sender; } } |
Step 5:
Code the recycleview adapter.
1 2 3 4 5 6 7 8 9 10 11 |
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.example.recyclerview.Model.MessageModel; import com.example.recyclerview.R; import java.util.ArrayList; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
public class ChatAdapter extends RecyclerView.Adapter<ChatAdapter.ViewHolder> { Context context = null; ArrayList<MessageModel> chatList = null; private final int SENT_MESSAGE = 0, RECEIVED_MESSAGE = 1; public ChatAdapter(Context context, ArrayList<MessageModel> chatList) { this.context = context; this.chatList = chatList; } /*** * * @param position * @return the view type of the item at the position for the * purpose of recycling view * * By default it returns zero showing a single view type for the adapter. */ @Override public int getItemViewType(int position) { if (chatList.get(position).getSender()) { return SENT_MESSAGE; } else { return RECEIVED_MESSAGE; } } @Override public ChatAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = null; //Based on view type decide which type of view to supply with viewHolder switch (viewType) { case SENT_MESSAGE: view = LayoutInflater.from(parent.getContext()).inflate (R.layout.sent_message, parent, false); break; case RECEIVED_MESSAGE: view = LayoutInflater.from(parent.getContext()).inflate (R.layout.received_message, parent, false); break; } return new ViewHolder(view); } @Override public void onBindViewHolder(ChatAdapter.ViewHolder holder, int position) { MessageModel model = chatList.get(position); holder.texttosend.setText(model.getMessage()); holder.date.setText(model.getTime()); } @Override public int getItemCount() { return chatList.size(); } /* * Here we have kept ID's of all the child row elements same. * But we can also create to different viewHolder classes * for different child rows. */ public class ViewHolder extends RecyclerView.ViewHolder { TextView texttosend; TextView date; public ViewHolder(View itemView) { super(itemView); texttosend = (TextView) itemView.findViewById(R.id.message); date = (TextView) itemView.findViewById(R.id.date); } } } |
Step 6:
Assign adapter to our recyclerview and set appropriate methods on recyclerview to arrange like chat. (MainActivity.java)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.Button; import android.widget.EditText; import com.example.recyclerview.Adapter.ChatAdapter; import com.example.recyclerview.Model.MessageModel; import com.example.recyclerview.R; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
public class MainActivity extends AppCompatActivity implements View.OnClickListener { ArrayList<MessageModel> chatlist = null; ChatAdapter adapter = null; RecyclerView chat_list; Button receive_button, send_button; // EditText editText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); chat_list = (RecyclerView) findViewById(R.id.chat_list); send_button = (Button) findViewById(R.id.send_button); receive_button = (Button) findViewById(R.id.receive_button); send_button.setOnClickListener(this); receive_button.setOnClickListener(this); LinearLayoutManager layoutManager = new LinearLayoutManager(this); /* * When stackFromEnd is true the list fills its content * starting from the bottom of the view. */ layoutManager.setStackFromEnd(true); chat_list.setLayoutManager(layoutManager); chatlist = new ArrayList<>(); adapter = new ChatAdapter(this, chatlist); chat_list.setAdapter(adapter); } @Override public void onClick(View v) { int id = v.getId(); EditText editText = (EditText) findViewById(R.id.texttosend); String text = null; if (editText != null) { text = editText.getText().toString().trim(); } // count will give us the position(last) where we will insert item int count = adapter.getItemCount(); if (text != null && text.length() != 0) { MessageModel model; Calendar calendar = Calendar.getInstance(); SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm"); String time = dateFormat.format(calendar.getTime()); model = new MessageModel(); model.setMessage(text); model.setSender(true); model.setTime(time); if (id == R.id.send_button) { model.setSender(true); } else if (id == R.id.receive_button) { model.setSender(false); } chatlist.add(model); adapter.notifyItemInserted(count); /* * void scrollToPosition(int position) tells layout manager to scroll recyclerView * to given position */ chat_list.scrollToPosition(count); editText.setText(""); } } } |
Step 7:
Run and chat with yourself ๐
Please Help. How can I load data from json into this
Bhai ye adapter wala jo variable use ke ha ye kis cclass ka ha?