[Android] RecyclerView trong Android
Chào các bạn, đã lâu lâu rồi không viết blog, trong bài viết này mình sẽ giới thiệu và hướng dẫn các bạn sử dụng cơ bản về RecyclerView trong Android.
Nội dung
RecyclerView là gì
RecyclerView là một View mới trong android giống như ListView nhưng mạnh mẽ hơn rất nhiều.
RecyclerView cho phép chúng ta load dữ liệu nhiều hơn ListView, vuốt mượt hơn, hiệu ứng đẹp hơn và hỗ trợ đa dạng layout của các phần tử trong danh sách.
Sử dụng RecyclerView trong Eclipse
Không biết máy của các bạn có mạnh để dùng được Android Studio một cách mượt mà không nhưng với “vợ” của mình thì nó có thể bốc cháy khi bật Android Studio. Vì vậy mình dùng Eclipse là đủ rồi. Tuy nhiên thì hầu hết các hướng dẫn bây giờ đều hướng dẫn các bạn làm trên Android Studio nên mình đưa thêm phần này vào cho bạn nào có “cảnh ngộ” giống mình.
Các bạn vào thư mục chứa sdk và tim đến thư mục: sdk\extras\android\m2repository\com\android\support\recyclerview-v7\22.1.1 (cái thư mục 22.1.1 là phiên bản sdk của mình dùng, còn của bạn dùng bản nào thì vào thư mục đó) và các bạn sẽ thấy file recyclerview-v7-22.1.1.aar, bạn copy nó ra chỗ khác, đổi tên nó thành recyclerview-v7-22.1.1.zip (Nếu dùng windows thì nhớ cho hiện đuôi của nó lên) và giải nén ra bạn sẽ thấy 1 file classes.jar, đây là file thư viện chúng ta cần dùng. Bạn có thể đổi tên nó cho dễ nhớ, mình đổi nó thành recyclerview.jar. Bạn copy nó vào thư mục lib trong project là xong.
Sử dụng RecyclerView trong Android Studio
Nếu bạn dùng Android studio thì theo lời thiên hạ đồn, mình chưa có kiểm chứng là bạn thêm dòng sau vào file Gradle:
compile 'com.android.support:recyclerview-v7:21.0.+'
Code tạo Danh sách bằng RecyclerView
Trước tiên các bạn hãy tạo project như bình thường, xong xuôi chúng ta bắt đầu code…
Giao diện XML
Trước tiên lag giao diện của 1 phần tử trong danh sách gồm có text và 1 nút xóa. File item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:orientation="horizontal" android:paddingLeft="8dp" android:paddingRight="8dp" > <TextView android:id="@+id/tv_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="8dp" android:layout_weight="1" /> <ImageButton android:id="@+id/btn_delete" android:layout_width="32dp" android:layout_height="32dp" android:src="@drawable/ic_delete" /> </LinearLayout>
Trong code trên
Sau đó tạo giao diện của Activity gồm 1 EditText nhập text, 1 button Add, và một RecyclerView hiển thị danh sách. File activity_main.xml
<LinearLayout 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" android:orientation="vertical" tools:context=".MainActivity" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <EditText android:id="@+id/edit_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="name" /> <Button android:id="@+id/btn_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Add" /> </LinearLayout> <android.support.v7.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical" /> </LinearLayout>
Code xử lý java
Trước tiên chúng ta tạo ra một class Data chứa dữ liệu của 1 phần tử, trong này mình ví dụ có tên thôi. FIle Data.java
package cachhoc.net.samplerecyclerview; public class Data { private String name; public Data(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Tiếp theo, giống như khi tùy biến ListView, chúng ta cần tạo 1 adapter riêng. Và ở đây cũng vậy, chúng ta tạo ra 1 adapter cho Recyclerview. File CustomRecyclerAdapter.java
package cachhoc.net.samplerecyclerview; import java.util.ArrayList; import java.util.List; import cachhoc.net.samplerecyclerview.CustomRecyclerAdapter.RecyclerViewHolder; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.TextView; public class CustomRecyclerAdapter extends RecyclerView.Adapter<RecyclerViewHolder> { private List<Data> listData = new ArrayList<Data>(); public CustomRecyclerAdapter(List<Data> listData) { this.listData = listData; } public void updateList(List<Data> data) { listData = data; notifyDataSetChanged(); } @Override public int getItemCount() { return listData.size(); } @Override public RecyclerViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) { LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext()); View itemView = inflater.inflate(R.layout.item, viewGroup, false); return new RecyclerViewHolder(itemView); } @Override public void onBindViewHolder(RecyclerViewHolder viewHolder, int position) { viewHolder.tvName.setText(listData.get(position).getName()); } public void addItem(int position, Data data) { listData.add(position, data); notifyItemInserted(position); } public void removeItem(int position) { listData.remove(position); notifyItemRemoved(position); } /** * ViewHolder for item view of list * */ public class RecyclerViewHolder extends RecyclerView.ViewHolder implements OnClickListener { public TextView tvName; public ImageButton btnDelete; public RecyclerViewHolder(View itemView) { super(itemView); tvName = (TextView) itemView.findViewById(R.id.tv_name); btnDelete = (ImageButton) itemView.findViewById(R.id.btn_delete); // set listener for button delete btnDelete.setOnClickListener(this); } // remove item when click button delete @Override public void onClick(View v) { removeItem(getAdapterPosition()); } } }
Trong code trên các bạn để ý một chút, nó khác ListView đó.
Phương thức onCreateViewHolder có chức năng tương tự getView khi dùng ListView, nó để tìm đến giao diện của 1 phần tử, chính là item.xml đã xây dựng bên trên nhưng khi trả về chúng ta trả về RecyclerViewHolder.
Phương thức onBindViewHolder được gọi để đặt các giá trị trong các phần tử.
RecyclerViewHolder là 1 class chứa các thuộc tính mà một phần tử có (text name và button delete). Trong RecyclerViewHolder các bạn cũng chú ý là chúng ta bắt sự kiện cho button delete tại đây chứ không bắt trong onCreateViewHolder vì khi bắt sự kiện chúng ta cần biết vị trí (position) thông qua phương thức getAdapterPosition chứ không nên bắt trong onCreateViewHolder sẽ dẫn đến sai sót.
Cuối cùng là viết code cho MainActivity. Cái này thì dễ rùi. File MainActivity.java
package cachhoc.net.samplerecyclerview; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; public class MainActivity extends Activity implements OnClickListener { private RecyclerView recyclerView; private CustomRecyclerAdapter adapter; private RecyclerView.LayoutManager layoutManager; private EditText editName; private List<Data> listData = new ArrayList<Data>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // connect views. editName = (EditText) findViewById(R.id.edit_name); recyclerView = (RecyclerView) findViewById(R.id.recycler); // If the size of views will not change as the data changes. recyclerView.setHasFixedSize(true); // Setting the LayoutManager. layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); // Setting the adapter. adapter = new CustomRecyclerAdapter(listData); recyclerView.setAdapter(adapter); // set listener for button add ((Button) findViewById(R.id.btn_add)).setOnClickListener(this); } // Called when add button is clicked. public void addItem() { // get data. Data dataToAdd = new Data(editName.getText().toString()); // Update adapter. adapter.addItem(listData.size(), dataToAdd); } @Override public void onClick(View v) { addItem(); } }
Các bạn có thể download project (thực hiện trên eclipse) Sample Recyclerview
Chào bạn Nguyenvanquan7826 ,
Cho mình hỏi khi gọi phương thức removeItem(getAdapterPosition()) ở trên thì tham số truyền vào là position. Mình thử cả getAdapterPosition() và getLayoutPosition() thì kết quả hiển thị trên RecyclerView đều giống nhau. Vậy bạn cho mình hỏi điểm khác nhau của 2 phương thức getAdapterPosition() và getLayoutPosition() là gì ?
Cái này nó hơi phức tạp chút.
Khi bạn có nhiều dữ liệu và thời gian tính toán để load dữ liệu lâu (như khi bạn load Gmail vậy) thì khi đó adapter đang thay đổi dữ liệu nhưng Giao diện thì chưa. Trong khoảng thời gian đó sẽ có sự khác nhau giữ 2 phương thức này.
Bạn có thể đọc thêm tại đây:
https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#getAdapterPosition()
Thanks nguyenvanquan7826 !
hi anh. em dùng
View viewItem = LayoutInflater.from(context).inflate(R.layout.layout_item_news_feed, parent, false);
thi bị khoảng trắng trên giao diện.
còn dùng
View viewItem = LayoutInflater.from(context).inflate(R.layout.layout_item_news_feed, null);
thì ko sao. nhưng có vẽ như ko đúng.
Anh giải đáp giúp em với ạ. Thanks anh!