ภาพรวม
การเลื่อน RecyclerView ไปยังตำแหน่งเฉพาะ (เช่น ไปด้านบนสุด) ใช้ Method ของ RecyclerView หรือ LinearLayoutManager มีหลายวิธี เลือกใช้ตาม Use Case
Method หลัก
| Method | คำอธิบาย | Animation |
|---|---|---|
smoothScrollToPosition(int position) | เลื่อนไป Position นั้น แบบ Smooth (Animation) | มี |
scrollToPosition(int position) | เลื่อนไป Position นั้น ทันที (No Animation) | ไม่มี |
layoutManager.scrollToPositionWithOffset(pos, offset) | เลื่อนไป Position พร้อม Offset จากขอบบน (px) | ไม่มี |
smoothScrollBy(dx, dy) | เลื่อนระยะทาง Px (Relative) | มี |
ตัวอย่าง: FloatingActionButton กดเพื่อ Scroll Top
1. 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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="100dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabScrollTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:contentDescription="Scroll to top"
android:src="@android:drawable/arrow_up_float"
app:backgroundTint="@color/design_default_color_primary"
app:fabSize="normal" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
2. MainActivity.java
package com.example.myapplication;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private StudentAdapter adapter;
private FloatingActionButton fabScrollTop;
private LinearLayoutManager layoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerView);
fabScrollTop = findViewById(R.id.fabScrollTop);
// LayoutManager (เก็บ Reference ไว้ใช้)
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
adapter = new StudentAdapter();
recyclerView.setAdapter(adapter);
// Generate 50 Items
List students = new ArrayList<>();
for (int i = 1; i <= 50; i++) {
students.add(new Student(UUID.randomUUID().toString(), "นักเรียน " + i, 15 + (i % 10)));
}
adapter.setStudents(students);
// FAB: Scroll to Top (Smooth)
fabScrollTop.setOnClickListener(v -> {
// วิธีที่ 1: RecyclerView.smoothScrollToPosition (ง่ายที่สุด)
recyclerView.smoothScrollToPosition(0);
// วิธีที่ 2: LinearLayoutManager (ควบคุมรายละเอียดมากกว่า)
// layoutManager.scrollToPositionWithOffset(0, 0); // ไม่มี Animation
// recyclerView.smoothScrollToPosition(0); // เหมือนวิธี 1
});
// Optional: ซ่อน FAB เมื่ออยู่ด้านบน แสดงเมื่อ Scroll ลง
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView rv, int dx, int dy) {
super.onScrolled(rv, dx, dy);
// แสดง FAB เมื่อ Scroll ลงมากว่า 5 Item
if (layoutManager.findFirstVisibleItemPosition() > 5) {
fabScrollTop.show();
} else {
fabScrollTop.hide();
}
}
});
}
}
Scroll ไปตำแหน่งเฉพาะ (Not Just Top)
// Scroll ไป Item ที่ 10 (Index 10) แบบ Smooth recyclerView.smoothScrollToPosition(10); // Scroll ไป Item ที่ 10 พร้อม Offset 50dp จากขอบบน (ต้องแปลง dp→px) int offsetPx = (int) (50 * getResources().getDisplayMetrics().density); layoutManager.scrollToPositionWithOffset(10, offsetPx); // ทันที (No Anim) // Scroll ไป Item ที่ 10 แบบ Smooth + Offset (Custom) recyclerView.smoothScrollToPosition(10); // แล้วใน OnScrollListener เช็คเมื่อถึง Item 10 ค่อย scrollBy offset เพิ่ม
SmoothScroller แบบ Custom (ควบคุมความเร็ว/ขั้นตอน)
// Custom LinearSmoothScroller: ควบคุมความเร็ว (px per ms)
LinearSmoothScroller scroller = new LinearSmoothScroller(this) {
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 100f / displayMetrics.densityDpi; // 100ms per inch (ปรับค่านี้)
}
};
scroller.setTargetPosition(0);
layoutManager.startSmoothScroll(scroller);
Scroll Listener Patterns
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView rv, int dx, int dy) {
int firstVisible = layoutManager.findFirstVisibleItemPosition();
int lastVisible = layoutManager.findLastVisibleItemPosition();
int totalCount = layoutManager.getItemCount();
// 1. Detect Reach Top
if (firstVisible == 0) {
View firstView = layoutManager.findViewByPosition(0);
if (firstView != null && firstView.getTop() >= 0) {
// อยู่ที่ Top จริงๆ
}
}
// 2. Detect Reach Bottom (Load More)
if (lastVisible >= totalCount - 3) { // เหลือ 3 Item
// loadMore();
}
// 3. Hide/Show FAB/Toolbar ตามทิศทาง Scroll
if (dy > 0 && fab.isShown()) fab.hide(); // Scroll Down
else if (dy < 0 && !fab.isShown()) fab.show(); // Scroll Up
}
});
GridLayoutManager / StaggeredGridLayoutManager
Method เดียวกันใช้ได้ แต่ findFirstVisibleItemPosition() อาจคืนค่าต่างกัน (Span) ใช้ findFirstVisibleItemPositions(int[]) แทน
สรุป
- scrollToTop Smooth:
recyclerView.smoothScrollToPosition(0)(ง่ายที่สุด) - Scroll ทันที:
layoutManager.scrollToPositionWithOffset(0, 0) - ซ่อน/แสดง FAB: ใช้
OnScrollListener+findFirstVisibleItemPosition() - Custom Speed: ใช้
LinearSmoothScrollerOverridecalculateSpeedPerPixel - ทำงานกับ LayoutManager ทุกชนิด (Linear, Grid, StaggeredGrid)