ตัวอย่างนี้สาธิตวิธี ตรวจจับทิศทางการ 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 มาตรฐาน
ทดสอบ
- รันแอป → แสดง ListView 50 รายการ
- เลื่อนลง → Log/Toast แสดง "Scrolling DOWN"
- เลื่อนขึ้น → Log/Toast แสดง "Scrolling UP"
📝 หมายเหตุ
AbsListView.OnScrollListener เป็น API เดิมสำหรับ ListView/GridView
สำหรับ RecyclerView ให้ใช้ RecyclerView.OnScrollListener ซึ่งมี dx, dy ใช้ง่ายกว่า