Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธี Scroll ไปด้านบน RecyclerView ด้วย LinearLayoutManager

ภาพรวม

การเลื่อน 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: ใช้ LinearSmoothScroller Override calculateSpeedPerPixel
  • ทำงานกับ LayoutManager ทุกชนิด (Linear, Grid, StaggeredGrid)