ภาพรวม
ตัวอย่างนี้แสดงวิธีใช้ GridLayoutManager กับ RecyclerView เพื่อแสดงข้อมูลในรูปแบบกริด (Grid) พร้อม AppBarLayout และ Toolbar ตาม Material Design
ขั้นตอนการสร้าง
ขั้นตอนที่ 1: สร้างโปรเจกต์และเพิ่ม Dependency
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.3.0'
implementation 'com.google.android.material:material:1.9.0'
}
ขั้นตอนที่ 2: Layout หลัก (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|snap"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
ขั้นตอนที่ 3: โค้ดหลัก (src/MainActivity.java)
package com.example.myapplication;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private CustomAdapter adapter;
private ArrayList<String> dataList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Toolbar
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle("GridLayoutManager Demo");
setSupportActionBar(toolbar);
// RecyclerView with GridLayoutManager
recyclerView = findViewById(R.id.recycler_view);
// 2 คอลัมน์ (spanCount = 2)
GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
adapter = new CustomAdapter(this, dataList, position -> {
dataList.remove(position);
adapter.notifyItemRemoved(position);
adapter.notifyItemRangeChanged(position, dataList.size());
});
recyclerView.setAdapter(adapter);
// Divider (Grid ใช้ทั้ง Horizontal และ Vertical)
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL));
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
// Sample data
for (int i = 0; i < 20; i++) {
dataList.add("Item " + (i + 1));
}
adapter.notifyDataSetChanged();
}
}
ขั้นตอนที่ 4: Adapter (src/CustomAdapter.java)
package com.example.myapplication;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.function.IntConsumer;
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
private Context context;
private ArrayList<String> dataList;
private IntConsumer onItemClick;
public CustomAdapter(Context context, ArrayList<String> dataList, IntConsumer onItemClick) {
this.context = context;
this.dataList = dataList;
this.onItemClick = onItemClick;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.grid_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.textView.setText(dataList.get(position));
holder.itemView.setOnClickListener(v -> {
if (onItemClick != null) onItemClick.accept(position);
});
}
@Override
public int getItemCount() {
return dataList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.title);
}
}
}
ขั้นตอนที่ 5: Item Layout (res/layout/grid_item.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="120dp"
app:cardElevation="4dp"
app:cardCornerRadius="8dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textStyle="bold"
android:gravity="center" />
</LinearLayout>
</androidx.cardview.widget.CardView>
GridLayoutManager Configuration
1. Span Count (จำนวนคอลัมน์)
// แนวนอน (Vertical scrolling) - 2 คอลัมน์ GridLayoutManager layoutManager = new GridLayoutManager(context, 2); // แนวตั้ง (Horizontal scrolling) - 3 แถว GridLayoutManager layoutManager = new GridLayoutManager(context, 3, GridLayoutManager.HORIZONTAL, false);
2. Span Size Lookup (รวมเซลล์ - Header/Footer/Full-width)
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (isHeader(position) || isFooter(position)) {
return spanCount; // กว้างเต็มจอ
}
return 1; // กว้าง 1 คอลัมน์
}
});
3. Gap Decoration (ช่องว่างระหว่าง Item)
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
private boolean includeEdge;
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int column = position % spanCount;
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount;
outRect.right = (column + 1) * spacing / spanCount;
if (position < spanCount) outRect.top = spacing;
outRect.bottom = spacing;
} else {
outRect.left = column * spacing / spanCount;
outRect.right = spacing - (column + 1) * spacing / spanCount;
if (position >= spanCount) outRect.top = spacing;
outRect.bottom = spacing;
}
}
}
// ใช้งาน
recyclerView.addItemDecoration(new GridSpacingItemDecoration(2, 16, true));
GridLayoutManager vs LinearLayoutManager vs StaggeredGridLayoutManager
| LayoutManager | เหมาะสำหรับ | คุณสมบัติ |
|---|---|---|
| LinearLayoutManager | List แนวตั้ง/แนวนอน | Simple, Efficient |
| GridLayoutManager | Grid เท่ากันทุก Cell | Uniform size, SpanSizeLookup |
| StaggeredGridLayoutManager | Grid ความสูงไม่เท่ากัน (Pinterest style) | Variable height, Gaps handling |
| FlexboxLayoutManager | Wrap content, Responsive | Flexbox CSS-like, Third-party |
การทดสอบ
รันแอป จะเห็น Grid 2 คอลัมน์ พร้อม Toolbar ที่ซ่อน/แสดงเมื่อ Scroll คลิก Item จะลบ Item นั้นออกพร้อม Animation