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.

GridLayoutManager vs StaggeredGridLayoutManager
| Đặc điểm | GridLayoutManager | StaggeredGridLayoutManager |
|---|---|---|
| Kích thước item | Cố định (cùng hàng bằng nhau) | Khác nhau (Pinterest style) |
| Span size | Hỗ trợ SpanSizeLookup | Hỗ trợ full span |
| Hiệu suất | Tốt hơn cho item đồng đều | Tính toán layout phức tạp hơn |