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

วิธีตรวจจับการ Scroll ขึ้น/ลงใน ListView Android ด้วย Kotlin

ตัวอย่างนี้สาธิตวิธี ตรวจจับทิศทางการ Scroll (ขึ้น/ลง) ใน ListView โดยใช้ OnScrollListener และเปรียบเทียบ firstVisibleItem

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

Android Studio → New Project → Empty Activity

ขั้นตอนที่ 2: Layout (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="8dp"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

ขั้นตอนที่ 3: โค้ดหลัก (MainActivity.kt)

import android.os.Bundle
import android.widget.AbsListView
import android.widget.ArrayAdapter
import android.widget.ListView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private lateinit var listView: ListView
    private var lastFirstVisibleItem = 0

    private val items = (1..50).map { "Item $it" }.toTypedArray()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        title = "ListView Scroll Detection"

        listView = findViewById(R.id.listView)
        val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, items)
        listView.adapter = adapter

        // 🔑 ตั้ง OnScrollListener
        listView.setOnScrollListener(object : AbsListView.OnScrollListener {
            override fun onScrollStateChanged(view: AbsListView, scrollState: Int) {
                // SCROLL_STATE_IDLE, TOUCH_SCROLL, FLING
            }

            override fun onScroll(
                view: AbsListView,
                firstVisibleItem: Int,
                visibleItemCount: Int,
                totalItemCount: Int
            ) {
                // 🔑 เปรียบเทียบ firstVisibleItem กับครั้งก่อน
                if (lastFirstVisibleItem < firstVisibleItem) {
                    // Scroll ลง (First visible item เพิ่มขึ้น)
                    Toast.makeText(
                        this@MainActivity,
                        "Scrolling DOWN - First visible: $firstVisibleItem",
                        Toast.LENGTH_SHORT
                    ).show()
                } else if (lastFirstVisibleItem > firstVisibleItem) {
                    // Scroll ขึ้น (First visible item ลดลง)
                    Toast.makeText(
                        this@MainActivity,
                        "Scrolling UP - First visible: $firstVisibleItem",
                        Toast.LENGTH_SHORT
                    ).show()
                }
                lastFirstVisibleItem = firstVisibleItem
            }
        })
    }
}

⚠️ ปัญหา: Toast แสดงบ่อยเกินไป

โค้ดด้านบนจะแสดง Toast ทุกครั้งที่ firstVisibleItem เปลี่ยน → **Spam Toast**
แก้ไขด้วย Debounce หรือ Log แทน:

override fun onScroll(...) {
    if (lastFirstVisibleItem != firstVisibleItem) {
        val direction = if (lastFirstVisibleItem < firstVisibleItem) "DOWN" else "UP"
        Log.d("ScrollDetect", "Scrolling $direction: firstVisible=$firstVisibleItem")
        // หรือ Debounce: ใช้ Handler postDelayed / Coroutine
        lastFirstVisibleItem = firstVisibleItem
    }
}

🔧 RecyclerView (แนะนำแทน ListView)

recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)
        if (dy > 0) {
            // Scroll UP (Content moves up)
            Log.d("Scroll", "Scrolling UP")
        } else if (dy < 0) {
            // Scroll DOWN (Content moves down)
            Log.d("Scroll", "Scrolling DOWN")
        }
    }
})

💡 Use Cases

  • ซ่อน/แสดง Toolbar/FAB ตามทิศทาง Scroll
  • Infinite Scroll / Pagination (โหลดเพิ่มเมื่อเลื่อนถึงล่าง)
  • Pull-to-Refresh Trigger
  • Analytics: วัดการอ่านเนื้อหา

ขั้นตอนที่ 4: AndroidManifest.xml

Manifest มาตรฐาน

ทดสอบ

  1. รันแอป → แสดง ListView 50 รายการ
  2. เลื่อนลง → Log/Toast แสดง "Scrolling DOWN"
  3. เลื่อนขึ้น → Log/Toast แสดง "Scrolling UP"

📝 หมายเหตุ

AbsListView.OnScrollListener เป็น API เดิมสำหรับ ListView/GridView
สำหรับ RecyclerView ให้ใช้ RecyclerView.OnScrollListener ซึ่งมี dx, dy ใช้ง่ายกว่า