Giới thiệu
Bài viết hướng dẫn cách phát hiện cử chỉ vuốt (swipe) theo 4 hướng: trái, phải, lên, xuống trên Android sử dụng GestureDetector và Kotlin.
Các bước thực hiện
Bước 1: Tạo dự án mới
Android Studio > File > New Project > hoàn tất.
Bước 2: Layout giao diện (activity_main.xml)
Một RelativeLayout đơn giản với TextView hướng dẫn:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="70dp"
android:background="#008080"
android:padding="5dp"
android:text="TutorialsPoint"
android:textColor="#fff"
android:textSize="24sp"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Vuốt để phát hiện sự kiện"
android:textAlignment="center"
android:textColor="@android:color/holo_purple"
android:textSize="24sp"
android:textStyle="bold" />
</RelativeLayout>
Bước 3: Logic xử lý vuốt (MainActivity.kt)
Triển khai OnSwipeTouchListener dựa trên GestureDetector.SimpleOnGestureListener:
import android.content.Context
import android.os.Bundle
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlin.math.abs
class MainActivity : AppCompatActivity() {
private var onSwipeTouchListener: OnSwipeTouchListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
title = "KotlinApp"
onSwipeTouchListener = OnSwipeTouchListener(this, findViewById(R.id.relativeLayout))
}
inner class OnSwipeTouchListener internal constructor(
ctx: Context,
mainView: View
) : View.OnTouchListener {
private val gestureDetector: GestureDetector
private var context: Context
private lateinit var onSwipe: OnSwipeListener
companion object {
private const val SWIPE_THRESHOLD = 100
private const val SWIPE_VELOCITY_THRESHOLD = 100
}
init {
gestureDetector = GestureDetector(ctx, GestureListener())
mainView.setOnTouchListener(this)
context = ctx
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event)
}
inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean = true
override fun onFling(
e1: MotionEvent,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
var result = false
try {
val diffY = e2.y - e1.y
val diffX = e2.x - e1.x
if (abs(diffX) > abs(diffY)) {
// Vuốt ngang
if (abs(diffX) > SWIPE_THRESHOLD && abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) onSwipeRight() else onSwipeLeft()
result = true
}
} else {
// Vuốt dọc
if (abs(diffY) > SWIPE_THRESHOLD && abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) onSwipeBottom() else onSwipeTop()
result = true
}
}
} catch (e: Exception) {
e.printStackTrace()
}
return result
}
}
// Các callback hướng vuốt
internal fun onSwipeRight() {
Toast.makeText(context, "Vuốt phải", Toast.LENGTH_SHORT).show()
onSwipe.swipeRight()
}
internal fun onSwipeLeft() {
Toast.makeText(context, "Vuốt trái", Toast.LENGTH_SHORT).show()
onSwipe.swipeLeft()
}
internal fun onSwipeTop() {
Toast.makeText(context, "Vuốt lên", Toast.LENGTH_SHORT).show()
onSwipe.swipeTop()
}
internal fun onSwipeBottom() {
Toast.makeText(context, "Vuốt xuống", Toast.LENGTH_SHORT).show()
onSwipe.swipeBottom()
}
internal interface OnSwipeListener {
fun swipeRight()
fun swipeTop()
fun swipeBottom()
fun swipeLeft()
}
}
}
Bước 4: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.swipedetection">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Chạy và kiểm tra
Chạy app, vuốt màn hình theo 4 hướng. Mỗi hướng sẽ hiển thị Toast tương ứng. Bạn có thể mở rộng interface OnSwipeListener để xử lý logic nghiệp vụ cụ thể (chuyển tab, xóa item, v.v.).
Giải thích ngưỡng (Threshold)
SWIPE_THRESHOLD = 100: Khoảng cách tối thiểu (pixel) để coi là một cử chỉ vuốt.SWIPE_VELOCITY_THRESHOLD = 100: Tốc độ tối thiểu (pixel/giây) để phân biệt vuốt với kéo thả chậm.- Có thể điều chỉnh các giá trị này tùy theo độ nhạy mong muốn.