Giới thiệu
Tiếp nối các bài viết về RecycylerView hôm nay tôi sẽ giới thiệu cho các bạn ReyclerView nâng cao hơn rất nhiều đó là RecyclerView có nhiều row khác nhau hay được gọi là RecyclerView Multiple View Type. Tôi nghĩ rằng các bạn thấy RecyclerView này rất nhiều ví dụ như new feed của Facebook. Và cách tạo ra ReyclerView Multiple View Type như thế nào thì bài viết này sẽ hướng dẫn các bạn.
Nếu bạn nào chưa có kiến thức về RecyclerView trong Android thì hãy xem lại 2 bài viết của tôi ở link dưới đây:
Sử dụng RecyclerView trong Android
Xử Lý Animation Trong RecyclerView
Tất cả ví dụ trong bài viết đều được viết trên Android Studio 2.1.2
Custom Adapter RecyclerView Multiple View Type
Việc chúng ta xây dựng RecylerView có nhiều row item khác nhau cũng giống như RecyclerView chỉ có 1 row item nhưng có một chút khác biệt ở ở Custom Adapter như sau:
+ Phải tạo n ViewHolder ứng với n row item.
+ Override lại phương thức getItemViewType(int position) để lấy về type tương ứng với từng position trong collection
+ Trong phương thức onCreateViewHolder phải dựa vào type để tạo ViewHolder tương ứng.
+ Trong phương thức onBindViewHolder cũng phải dựa vào type để bind data tương ứng vào ViewHolder.
Sau đây tôi sẽ đi vào phần viết CustomAdapter.
Trước tiên tôi tạo ba file xml tương ứng với 3 row item như sau:
- row_text.xml: Đơn giản row item này có một TextView để hiển thị text.
- row_image.xml: Row item hiển thị một hình ảnh ImageView.
- row_user.xml: Row item này gồm có 2 TextView hiển thị tên và địa chỉ của user.
File row_text.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_marginTop="3dp" android:layout_height="wrap_content"> <TextView android:background="#ecf0f1" android:padding="5dp" android:textColor="#2c3e50" android:id="@+id/tv_text" android:layout_width="match_parent" android:layout_height="wrap_content" /> </FrameLayout> |
File row_image.xml
1 2 3 4 5 6 7 8 9 10 11 12 |
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="3dp"> <ImageView android:id="@+id/imv_image" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#95a5a6" /> </FrameLayout> |
File row_user.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?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_marginTop="3dp" android:background="#bdc3c7" android:orientation="vertical"> <TextView android:id="@+id/tv_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#34495e" android:textSize="18dp" /> <TextView android:id="@+id/tv_address" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#16a085" android:textSize="16dp" /> </LinearLayout> |
Class User.java lưu thông tin User
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 |
package com.eitguide.nguyennghia.recyclerviewmultipleviewtype; /** * Created by nguyennghia on 8/28/16. */ public class User { private String name; private String address; public User() { } public User(String name, String address) { this.name = name; this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } |
Tiếp theo chúng ta tạo một CustomAdapter:
Có 3 ViewHolder như sau:
TextViewHolder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class TextViewHolder extends RecyclerView.ViewHolder { private TextView tvText; public TextViewHolder(View itemView) { super(itemView); tvText = (TextView) itemView.findViewById(R.id.tv_text); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(mContext, mObjects.get(getAdapterPosition()).toString(), Toast.LENGTH_SHORT).show(); } }); } } |
ImageViewHolder:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class ImageViewHolder extends RecyclerView.ViewHolder { private ImageView imvImage; public ImageViewHolder(View itemView) { super(itemView); imvImage = (ImageView) itemView.findViewById(R.id.imv_image); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(mContext, mObjects.get(getAdapterPosition()).toString(), Toast.LENGTH_SHORT).show(); } }); } } |
UserViewHolder:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class UserViewHolder extends RecyclerView.ViewHolder { private TextView tvName; private TextView tvAddess; public UserViewHolder(View itemView) { super(itemView); tvName = (TextView) itemView.findViewById(R.id.tv_name); tvAddess = (TextView) itemView.findViewById(R.id.tv_address); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { User user = (User) mObjects.get(getAdapterPosition()); Toast.makeText(mContext, user.getName() + ", " + user.getAddress(), Toast.LENGTH_SHORT).show(); } }); } |
Override lại phương thức getItemViewType
1 2 3 4 5 6 7 8 9 10 11 |
@Override public int getItemViewType(int position) { if (mObjects.get(position) instanceof String) return TEXT; else if (mObjects.get(position) instanceof Integer) return IMAGE; else if (mObjects.get(position) instanceof User) return USER; return -1; } |
Xử lý trong phương thức onCreateViewType
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater li = LayoutInflater.from(mContext); switch (viewType) { case TEXT: View itemView0 = li.inflate(R.layout.row_text, parent, false); return new TextViewHolder(itemView0); case IMAGE: View itemView1 = li.inflate(R.layout.row_image, parent, false); return new ImageViewHolder(itemView1); case USER: View itemView2 = li.inflate(R.layout.row_user, parent, false); return new UserViewHolder(itemView2); default: break; } return null; } |
onBindViewHolder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (getItemViewType(position)) { case TEXT: TextViewHolder textViewHolder = (TextViewHolder) holder; textViewHolder.tvText.setText(mObjects.get(position).toString()); break; case IMAGE: ImageViewHolder imageViewHolder = (ImageViewHolder) holder; imageViewHolder.imvImage.setImageResource((int) mObjects.get(position)); break; case USER: User user = (User) mObjects.get(position); UserViewHolder userViewHolder = (UserViewHolder) holder; userViewHolder.tvName.setText(user.getName()); userViewHolder.tvAddess.setText(user.getAddress()); break; } } |
Và đây là Source code toàn bộ class CustomAdapter.java
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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
package com.eitguide.nguyennghia.recyclerviewmultipleviewtype; import android.content.Context; import android.media.ImageWriter; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import java.util.List; /** * Created by nguyennghia on 8/28/16. */ public class CustomAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private Context mContext; private List<Object> mObjects; public static final int TEXT = 0; public static final int IMAGE = 1; public static final int USER = 2; public CustomAdapter(Context context, List<Object> objects) { mContext = context; mObjects = objects; } @Override public int getItemViewType(int position) { if (mObjects.get(position) instanceof String) return TEXT; else if (mObjects.get(position) instanceof Integer) return IMAGE; else if (mObjects.get(position) instanceof User) return USER; return -1; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater li = LayoutInflater.from(mContext); switch (viewType) { case TEXT: View itemView0 = li.inflate(R.layout.row_text, parent, false); return new TextViewHolder(itemView0); case IMAGE: View itemView1 = li.inflate(R.layout.row_image, parent, false); return new ImageViewHolder(itemView1); case USER: View itemView2 = li.inflate(R.layout.row_user, parent, false); return new UserViewHolder(itemView2); default: break; } return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (getItemViewType(position)) { case TEXT: TextViewHolder textViewHolder = (TextViewHolder) holder; textViewHolder.tvText.setText(mObjects.get(position).toString()); break; case IMAGE: ImageViewHolder imageViewHolder = (ImageViewHolder) holder; imageViewHolder.imvImage.setImageResource((int) mObjects.get(position)); break; case USER: User user = (User) mObjects.get(position); UserViewHolder userViewHolder = (UserViewHolder) holder; userViewHolder.tvName.setText(user.getName()); userViewHolder.tvAddess.setText(user.getAddress()); break; } } @Override public int getItemCount() { return mObjects.size(); } public class UserViewHolder extends RecyclerView.ViewHolder { private TextView tvName; private TextView tvAddess; public UserViewHolder(View itemView) { super(itemView); tvName = (TextView) itemView.findViewById(R.id.tv_name); tvAddess = (TextView) itemView.findViewById(R.id.tv_address); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { User user = (User) mObjects.get(getAdapterPosition()); Toast.makeText(mContext, user.getName() + ", " + user.getAddress(), Toast.LENGTH_SHORT).show(); } }); } } public class TextViewHolder extends RecyclerView.ViewHolder { private TextView tvText; public TextViewHolder(View itemView) { super(itemView); tvText = (TextView) itemView.findViewById(R.id.tv_text); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(mContext, mObjects.get(getAdapterPosition()).toString(), Toast.LENGTH_SHORT).show(); } }); } } public class ImageViewHolder extends RecyclerView.ViewHolder { private ImageView imvImage; public ImageViewHolder(View itemView) { super(itemView); imvImage = (ImageView) itemView.findViewById(R.id.imv_image); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(mContext, mObjects.get(getAdapterPosition()).toString(), Toast.LENGTH_SHORT).show(); } }); } } } |
Sau khi đã tạo xong CustomAdapter việc còn lại chúng ta chỉ add RecyclerView vào main_activity.xml và setup cho RecyclerView trong MainActivity.java như sau:
File main_activity.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.eitguide.nguyennghia.recyclerviewmultipleviewtype.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/rv_multipe_view_type" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> |
Setup trong MainActivity.java
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 |
package com.eitguide.nguyennghia.recyclerviewmultipleviewtype; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private RecyclerView rvMultipleViewType; private List<Object> mData; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); rvMultipleViewType = (RecyclerView) findViewById(R.id.rv_multipe_view_type); mData = new ArrayList<>(); mData.add(new User("Nguyen Van Nghia", "Quan 11")); mData.add(R.drawable.avatar_1); mData.add("Text 0"); mData.add("Text 1"); mData.add(new User("Nguyen Hoang Minh", "Quan 3")); mData.add("Text 2"); mData.add(R.drawable.avatar_2); mData.add(R.drawable.avatar_3); mData.add(new User("Pham Nguyen Tam Phu", "Quan 10")); mData.add("Text 3"); mData.add("Text 4"); mData.add(new User("Tran Van Phuc", "Quan 1")); mData.add(R.drawable.avatar_4); mData.add(R.drawable.avatar_5); mData.add("Text 5"); mData.add(new User("Nguyen Ngoc Tien", "Quan 11")); mData.add(R.drawable.avatar_6); CustomAdapter adapter = new CustomAdapter(this, mData); rvMultipleViewType.setAdapter(adapter); rvMultipleViewType.setLayoutManager(new LinearLayoutManager(this)); } } |
Các bạn thấy rằng mỗi phần tử trong List đều có kiểu Object. Bởi vì tôi muốn add bất cứ kiểu dữ liệu nào vào List này.
Chạy kết quả demo các bạn sẽ thấy một kết quả tuyệt vời như dưới đây:
Source code sử dụng trong bài viết: ReyclerViewMultipleViewType
Kết luận
Qua ba bài viết về RecyclerView tôi hy vọng rằng các bạn có thể vận dụng kiến thức mà tôi truyền đạt vào trong những Project của các bạn.
Có học vấn không có đạo đức như một kẻ xấu; có đạo đức không có học vấn như một người thô bỉ.
Roosevelt (Mỹ)