CyStack logo
  • Sản phẩm & Dịch vụ
  • Giải pháp
  • Bảng giá
  • Công ty
  • Tài liệu
Vi

vi

Trang chủHướng dẫnGridLayoutManager trong Android: hướng dẫn từng bước kèm ví dụ
Chuyên gia

GridLayoutManager trong Android: hướng dẫn từng bước kèm ví dụ

CyStack blog 4 phút để đọc
CyStack blog01/08/2025
Locker Avatar

Chris Pham

Technical Writer

Locker logo social
Reading Time: 4 minutes

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.

GridLayoutManager trong Android

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ính
  • RecyclerViewAdapter.java: Adapter cho RecyclerView
  • DataModel.java: Lớp mô hình dữ liệu
  • AutoFitGridLayoutManager.java: Lớp GridLayoutManager tù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();
    }
}

  1. Lớp trên triển khai giao diện RecyclerViewAdapter.ItemListener và ghi đè phương thức onItemClick đã được định nghĩa trong lớp Adapter. Bằng cách này, chúng ta đã triển khai Click Listener cho RecyclerView ngay trong Activity, thay vì xử lý trong lớp Adapter (tương tự như cách onItemClickListener hoạt động trong ListView).
  2. Lớp DataModel lưu trữ thông tin chi tiết cho từng phần tử trong RecyclerView.
  3. LayoutManager của RecyclerView có thể được thiết lập bằng hai cách: hoặc khởi tạo lớp AutoFitGridLayoutManager với độ rộng cột là 500, hoặc khởi tạo đối tượng GridLayoutManager và 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:

Tải xuống dự án Android GridLayoutManager

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất