GridLayoutManager trong Android là một triển khai của lớp RecyclerView.LayoutManager, được sử dụng để sắp xếp các phần tử theo dạng lưới.
Trong hướng dẫn này, chúng ta sẽ xây dựng một ứng dụng hiển thị các CardView bên trong RecyclerView theo bố cục lưới. Bên cạnh đó, chúng ta sẽ triển khai một giao diện nhằm bổ sung tính năng item click cho RecyclerView tương tự như cách onItemClickListener hoạt động trong ListView.

Sử dụng GridLayoutManager trong RecyclerView
Trước đây, chúng ta đã triển khai RecyclerView với LinearLayoutManager. Giờ đây, hãy sử dụng GridLayoutManager để hiển thị các phần tử theo dạng lưới. Cấu trúc hàm khởi tạo của GridLayoutManager như sau:
GridLayoutManager(Context context,
int spanCount,
int orientation,
boolean reverseLayout)
Tham số reverseLayout, nếu được đặt là true thì sẽ khiến các phần tử được hiển thị từ cuối lên đầu. Để thiết lập số cột chiếm dụng cho từng phần tử, chúng ta sử dụng phương thức setSpanSizeLookup trên GridLayoutManager. Bây giờ, hãy triển khai RecyclerView sử dụng GridLayoutManager trong một dự án Android Studio mới.
Cấu trúc dự án minh họa Android GridLayoutManager
Dự án bao gồm các thành phần sau:
MainActivity.java: Activity chínhRecyclerViewAdapter.java: Adapter cho RecyclerViewDataModel.java: Lớp mô hình dữ liệuAutoFitGridLayoutManager.java: LớpGridLayoutManagertùy chỉnh
Giao diện XML của lớp MainActivity.java được định nghĩa trong tệp activity_main.xml như sau:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayoutxmlns:android="<https://schemas.android.com/apk/res/android>"
xmlns:tools="<https://schemas.android.com/tools>"
xmlns:app="<https://schemas.android.com/apk/res-auto>"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<RelativeLayoutandroid:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerViewandroid:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
Lưu ý: Đừng quên thêm các dependency sau để sử dụng các widget củaMaterial Design và CardView trong tệp build.gradle.
compile 'com.android.support:cardview-v7:25.1.1'
compile 'com.android.support:design:25.1.1'
Lớp DataModel.java được trình bày dưới đây: package com.journaldev.recyclerviewgridlayoutmanager
public class DataModel {
public String text;
public int drawable;
public String color;
public DataModel(String t, int d, String c) {
text = t;
drawable = d;
color = c;
}
}
Lớp DataModel lưu thông tin văn bản, biểu tượng và màu nền của mỗi ô.
Lớp RecyclerViewAdapter.java được triển khai như sau:
package com.journaldev.recyclerviewgridlayoutmanager;
import android.content.Context;
import android.graphics.Color;
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.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayList;
public class RecyclerViewAdapter extends RecyclerView.Adapter {
ArrayList mValues;
Context mContext;
protected ItemListener mListener;
public RecyclerViewAdapter(Context context, ArrayList values, ItemListener itemListener) {
mValues = values;
mContext = context;
mListener=itemListener;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView textView;
public ImageView imageView;
public RelativeLayout relativeLayout;
DataModel item;
public ViewHolder(View v) {
super(v);
v.setOnClickListener(this);
textView = (TextView) v.findViewById(R.id.textView);
imageView = (ImageView) v.findViewById(R.id.imageView);
relativeLayout = (RelativeLayout) v.findViewById(R.id.relativeLayout);
}
public void setData(DataModel item) {
this.item = item;
textView.setText(item.text);
imageView.setImageResource(item.drawable);
relativeLayout.setBackgroundColor(Color.parseColor(item.color));
}
@Override
public void onClick(View view) {
if (mListener != null) {
mListener.onItemClick(item);
}
}
}
@Override
public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_view_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder Vholder, int position) {
Vholder.setData(mValues.get(position));
}
@Override
public int getItemCount() {
return mValues.size();
}
public interface ItemListener {
void onItemClick(DataModel item);
}
}
Trong đoạn mã trên, chúng ta đã định nghĩa một giao diện ItemListener, giao diện này sẽ được triển khai trong lớp MainActivity.java. Giao diện XML cho từng phần tử của RecyclerView được trình bày dưới đây trong tệp recycler_view_item.xml.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="<https://schemas.android.com/apk/res/android>"
xmlns:card_view="<https://schemas.android.com/apk/res-auto>"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardViewandroid:id="@+id/cardView"
android:layout_width="match_parent"
android:layout_height="150dp"
card_view:cardCornerRadius="0dp"
card_view:cardElevation="@dimen/margin10"
card_view:cardMaxElevation="@dimen/margin10"
card_view:contentPadding="@dimen/margin10">
<RelativeLayoutandroid:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_gravity="center">
<ImageViewandroid:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:tint="@android:color/white"
android:padding="5dp" />
<TextViewandroid:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@+id/imageView"
android:textColor="@android:color/white" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
Lớp AutoFitGridLayoutManager.java được trình bày dưới đây:
package com.journaldev.recyclerviewgridlayoutmanager;
import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
public class AutoFitGridLayoutManager extends GridLayoutManager {
private int columnWidth;
private boolean columnWidthChanged = true;
public class AutoFitGridLayoutManager extends GridLayoutManager {
private int columnWidth;
private boolean columnWidthChanged = true;
public AutoFitGridLayoutManager(Context context, int columnWidth) {
super(context, 1);
setColumnWidth(columnWidth);
}
public void setColumnWidth(int newColumnWidth) {
if (newColumnWidth > 0 && newColumnWidth != columnWidth) {
columnWidth = newColumnWidth;
columnWidthChanged = true;
}
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (columnWidthChanged && columnWidth > 0) {
int totalSpace = (getOrientation() == VERTICAL)
? getWidth() - getPaddingRight() - getPaddingLeft()
: getHeight() - getPaddingTop() - getPaddingBottom();
int spanCount = Math.max(1, totalSpace / columnWidth);
setSpanCount(spanCount);
columnWidthChanged = false;
}
super.onLayoutChildren(recycler, state);
}
}
Số lượng cột (span count) được tính toán động dựa trên hướng, chiều rộng và chiều cao hiện có. Lớp MainActivity.java được trình bày dưới đây:
ackage com.journaldev.recyclerviewgridlayoutmanager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity implements RecyclerViewAdapter.ItemListener {
RecyclerView recyclerView;
ArrayList arrayList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerView);
arrayList = new ArrayList();
arrayList.add(new DataModel("Item 1", R.drawable.battle, "#09A9FF"));
arrayList.add(new DataModel("Item 2", R.drawable.beer, "#3E51B1"));
arrayList.add(new DataModel("Item 3", R.drawable.ferrari, "#673BB7"));
arrayList.add(new DataModel("Item 4", R.drawable.jetpack_joyride, "#4BAA50"));
arrayList.add(new DataModel("Item 5", R.drawable.three_d, "#F94336"));
arrayList.add(new DataModel("Item 6", R.drawable.terraria, "#0A9B88"));
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, arrayList, this);
recyclerView.setAdapter(adapter);
// GridLayoutManager đơn giản với 2 cột
GridLayoutManager manager = new GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(manager);
// Có thể thay bằng:
// AutoFitGridLayoutManager layoutManager = new AutoFitGridLayoutManager(this, 500);
// recyclerView.setLayoutManager(layoutManager);
}
@Override
public void onItemClick(DataModel item) {
Toast.makeText(getApplicationContext(), item.text + " is clicked", Toast.LENGTH_SHORT).show();
}
}
- Lớp trên triển khai giao diện
RecyclerViewAdapter.ItemListenervà ghi đè phương thứconItemClickđã được định nghĩa trong lớp Adapter. Bằng cách này, chúng ta đã triển khai Click Listener choRecyclerViewngay trong Activity, thay vì xử lý trong lớp Adapter (tương tự như cáchonItemClickListenerhoạt động trong ListView). - Lớp
DataModellưu trữ thông tin chi tiết cho từng phần tử trongRecyclerView. LayoutManagercủaRecyclerViewcó thể được thiết lập bằng hai cách: hoặc khởi tạo lớpAutoFitGridLayoutManagervới độ rộng cột là 500, hoặc khởi tạo đối tượngGridLayoutManagervà thiết lập số lượng cột là 2.
Bây giờ, hãy cùng xem kết quả đầu ra của ứng dụng khi sử dụng mã GridLayoutManager tiêu chuẩn.
Như bạn có thể thấy, mỗi hàng hiển thị hai phần tử, các phần tử này được phân chia đều theo chiều rộng cột ở cả hai hướng màn hình.
Bây giờ, hãy chú thích đoạn mã sử dụng GridLayoutManager đơn giản và chạy lại ứng dụng với AutoFitGridLayoutManager:
AutoFitGridLayoutManager layoutManager = new AutoFitGridLayoutManager(this, 500);
recyclerView.setLayoutManager(layoutManager);
Kết quả hiển thị khi sử dụng AutoFitGridLayoutManager:
Như bạn thấy trong hình trên, khi thiết bị chuyển sang chế độ ngang (landscape), mỗi hàng hiển thị ba phần tử, cho thấy các phần tử đã được tự động điều chỉnh kích thước để phù hợp với chiều rộng cột.
Điều này cũng kết thúc hướng dẫn này. Bạn có thể tải xuống toàn bộ dự án Android GridLayoutManager từ liên kết dưới đây: