Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Cách sử dụng GridLayoutManager trong RecyclerView Android

Giới thiệu

GridLayoutManager hiển thị item RecyclerView theo lưới (grid) với số cột cố định hoặc tự động điều chỉnh. Hỗ trợ span size biến đổi cho header/footer/full-width item.

Các bước thực hiện

Bước 1: Dependency (build.gradle)

dependencies {
    implementation "androidx.recyclerview:recyclerview:1.3.0"
    implementation "com.google.android.material:material:1.9.0"
}

Bước 2: Giao diện chính (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:title="GridLayoutManager Demo" />

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Bước 3: Item Layout - CardView (res/layout/item_grid.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="12dp"
    app:cardElevation="4dp"
    app:cardUseCompatPadding="true"
    android:layout_margin="8dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="center"
        android:padding="16dp">

        <ImageView
            android:id="@+id/ivIcon"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:src="@mipmap/ic_launcher"
            android:contentDescription="@string/app_name" />

        <TextView
            android:id="@+id/tvTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:gravity="center"
            android:textSize="16sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/tvSubtitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Subtitle"
            android:textSize="12sp"
            android:textColor="?android:attr/textColorSecondary" />

    </LinearLayout>

</androidx.cardview.widget.CardView>

Bước 4: Model (src/GridItem.java)

package com.example.myapplication;

public class GridItem {
    public final String title;
    public final String subtitle;
    public final int iconRes;

    public GridItem(String title, String subtitle, int iconRes) {
        this.title = title;
        this.subtitle = subtitle;
        this.iconRes = iconRes;
    }
}

Bước 5: Adapter (src/GridAdapter.java)

package com.example.myapplication;

import android.content.Context;
import android.support.annotation.NonNull;
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 java.util.List;

public class GridAdapter extends RecyclerView.Adapter<GridAdapter.ViewHolder> {

    private List<GridItem> items;
    private OnItemClickListener listener;

    public interface OnItemClickListener {
        void onItemClick(int position, GridItem item);
    }

    public GridAdapter(List<GridItem> items, OnItemClickListener listener) {
        this.items = items;
        this.listener = listener;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_grid, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        GridItem item = items.get(position);
        holder.tvTitle.setText(item.title);
        holder.tvSubtitle.setText(item.subtitle);
        holder.ivIcon.setImageResource(item.iconRes);
        holder.itemView.setOnClickListener(v -> {
            if (listener != null) listener.onItemClick(position, item);
        });
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        ImageView ivIcon;
        TextView tvTitle, tvSubtitle;
        ViewHolder(View view) {
            super(view);
            ivIcon = view.findViewById(R.id.ivIcon);
            tvTitle = view.findViewById(R.id.tvTitle);
            tvSubtitle = view.findViewById(R.id.tvSubtitle);
        }
    }
}

Bước 6: MainActivity.java

package com.example.myapplication;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements GridAdapter.OnItemClickListener {

    RecyclerView recyclerView;
    GridAdapter adapter;
    List<GridItem> items = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        recyclerView = findViewById(R.id.recyclerView);
        // 2 cột, vertical scrolling
        GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
        recyclerView.setLayoutManager(layoutManager);

        // Tạo dữ liệu mẫu
        for (int i = 1; i <= 20; i++) {
            items.add(new GridItem("Item " + i, "Mô tả " + i, R.mipmap.ic_launcher));
        }

        adapter = new GridAdapter(items, this);
        recyclerView.setAdapter(adapter);
    }

    @Override
    public void onItemClick(int position, GridItem item) {
        Toast.makeText(this, "Clicked: " + item.title + " (pos " + position + ")", Toast.LENGTH_SHORT).show();
    }
}

Tính năng nâng cao: Span Size Lookup

Cho phép item chiếm nhiều cột (header, footer, banner full-width):

GridLayoutManager layoutManager = new GridLayoutManager(this, 3); // 3 cột
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
    @Override
    public int getSpanSize(int position) {
        if (position == 0) return 3; // Header chiếm 3 cột
        if (position == items.size() - 1) return 3; // Footer chiếm 3 cột
        return 1; // Item thường 1 cột
    }
});
recyclerView.setLayoutManager(layoutManager);

Chạy ứng dụng

Nhấn Run. RecyclerView hiển thị lưới 2 cột, cuộn mượt, Toolbar ẩn/hiện khi cuộn. Click item hiển thị Toast.

Cách sử dụng GridLayoutManager trong RecyclerView Android

GridLayoutManager vs StaggeredGridLayoutManager

Đặc điểmGridLayoutManagerStaggeredGridLayoutManager
Kích thước itemCố định (cùng hàng bằng nhau)Khác nhau (Pinterest style)
Span sizeHỗ trợ SpanSizeLookupHỗ trợ full span
Hiệu suấtTốt hơn cho item đồng đềuTính toán layout phức tạp hơn