Cử chỉ chạm xảy ra khi người dùng đặt một hoặc nhiều ngón tay trên màn hình cảm ứng và ứng dụng của bạn diễn giải mẫu chạm này là một cử chỉ. Có có hai giai đoạn để phát hiện cử chỉ:
- Thu thập dữ liệu sự kiện chạm.
- Diễn giải dữ liệu để xác định xem dữ liệu đó có đáp ứng các tiêu chí cho cử chỉ mà ứng dụng của bạn hỗ trợ.
Lớp AndroidX
Các ví dụ trong tài liệu này sử dụng
GestureDetectorCompat
và
MotionEventCompat
khác. Các lớp này nằm trong AndroidX
Thư viện. Sử dụng các lớp AndroidX khi có thể để cung cấp khả năng tương thích với
các thiết bị cũ hơn.
MotionEventCompat
không là lựa chọn thay thế cho
MotionEvent
. Thay vào đó, nó cung cấp các phương thức tiện ích tĩnh mà bạn truyền
MotionEvent
đối tượng để nhận thao tác liên quan đến đối tượng đó
sự kiện.
Thu thập dữ liệu
Khi người dùng đặt một hoặc nhiều ngón tay trên màn hình, thao tác này sẽ kích hoạt
số gọi lại
onTouchEvent()
trên khung hiển thị nhận sự kiện chạm. Đối với mỗi chuỗi thao tác chạm
các sự kiện—chẳng hạn như vị trí, áp lực, kích thước và các sự kiện khác
ngón tay—được xác định là một cử chỉ, onTouchEvent()
là
được kích hoạt nhiều lần.
Cử chỉ bắt đầu khi người dùng chạm vào màn hình lần đầu tiên, tiếp tục khi
hệ thống theo dõi vị trí ngón tay hoặc các ngón tay của người dùng và kết thúc bằng
ghi lại sự kiện cuối cùng khi người dùng rời khỏi màn hình.
Trong suốt tương tác này, MotionEvent
đã phân phối tới
onTouchEvent()
cung cấp thông tin chi tiết về mọi hoạt động tương tác. Ứng dụng của bạn
có thể sử dụng dữ liệu do MotionEvent
cung cấp để xác định xem
cử chỉ mà nó quan tâm sẽ xảy ra.
Ghi lại các sự kiện chạm cho một Hoạt động hoặc Chế độ xem
Để chặn các sự kiện chạm trong Activity
hoặc
View
, ghi đè lệnh gọi lại onTouchEvent()
.
Đoạn mã sau đây sử dụng
getAction()
để trích xuất hành động mà người dùng thực hiện từ tham số event
.
Thao tác này cung cấp cho bạn dữ liệu thô cần thiết để xác định xem liệu một cử chỉ mà bạn quan tâm hay không
vấn đề xảy ra.
Kotlin
class MainActivity : Activity() { ... // This example shows an Activity. You can use the same approach if you are // subclassing a View. override fun onTouchEvent(event: MotionEvent): Boolean { return when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(DEBUG_TAG, "Action was DOWN") true } MotionEvent.ACTION_MOVE -> { Log.d(DEBUG_TAG, "Action was MOVE") true } MotionEvent.ACTION_UP -> { Log.d(DEBUG_TAG, "Action was UP") true } MotionEvent.ACTION_CANCEL -> { Log.d(DEBUG_TAG, "Action was CANCEL") true } MotionEvent.ACTION_OUTSIDE -> { Log.d(DEBUG_TAG, "Movement occurred outside bounds of current screen element") true } else -> super.onTouchEvent(event) } } }
Java
public class MainActivity extends Activity { ... // This example shows an Activity. You can use the same approach if you are // subclassing a View. @Override public boolean onTouchEvent(MotionEvent event){ switch(event.getAction()) { case (MotionEvent.ACTION_DOWN) : Log.d(DEBUG_TAG,"Action was DOWN"); return true; case (MotionEvent.ACTION_MOVE) : Log.d(DEBUG_TAG,"Action was MOVE"); return true; case (MotionEvent.ACTION_UP) : Log.d(DEBUG_TAG,"Action was UP"); return true; case (MotionEvent.ACTION_CANCEL) : Log.d(DEBUG_TAG,"Action was CANCEL"); return true; case (MotionEvent.ACTION_OUTSIDE) : Log.d(DEBUG_TAG,"Movement occurred outside bounds of current screen element"); return true; default : return super.onTouchEvent(event); } }
Mã này tạo ra các thông báo như sau trong Logcat khi người dùng nhấn vào, thao tác chạm & giữ và kéo:
GESTURES D Action was DOWN GESTURES D Action was UP GESTURES D Action was MOVE
Đối với các cử chỉ tuỳ chỉnh, bạn có thể tự xử lý các sự kiện này để
xác định xem chúng có đại diện cho một cử chỉ bạn cần xử lý hay không. Tuy nhiên, nếu
ứng dụng dùng các cử chỉ phổ biến, chẳng hạn như nhấn đúp, chạm & giữ, hất, v.v.
bạn có thể tận dụng
GestureDetector
. GestureDetector
giúp bạn dễ dàng phát hiện những từ khoá thường gặp
mà không tự xử lý từng sự kiện chạm. Đây là
được thảo luận thêm trong bài viết Phát hiện cử chỉ.
Ghi lại các sự kiện chạm cho một chế độ xem
Thay vì onTouchEvent()
, bạn có thể đính kèm một
View.OnTouchListener
đối tượng cho View
bất kỳ
bằng cách sử dụng
setOnTouchListener()
. Điều này giúp bạn có thể theo dõi các sự kiện chạm mà không cần phân lớp con
View
hiện tại, như trong ví dụ sau:
Kotlin
findViewById<View>(R.id.my_view).setOnTouchListener { v, event -> // Respond to touch events. true }
Java
View myView = findViewById(R.id.my_view); myView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Respond to touch events. return true; } });
Lưu ý khi tạo trình nghe trả về false
cho
Sự kiện ACTION_DOWN
.
Nếu bạn làm như vậy, trình nghe sẽ không được gọi cho lượt
ACTION_MOVE
và
ACTION_UP
chuỗi
các sự kiện. Lý do là ACTION_DOWN
là điểm khởi đầu cho tất cả
sự kiện chạm.
Nếu đang tạo khung hiển thị tuỳ chỉnh, bạn có thể ghi đè
onTouchEvent()
, như mô tả trước đó.
Phát hiện cử chỉ
Android cung cấp lớp GestureDetector
để phát hiện các thuộc tính phổ biến
cử chỉ. Một số cử chỉ mà tính năng này hỗ trợ bao gồm
onDown()
,
onLongPress()
,
và
onFling()
.
Bạn có thể sử dụng GestureDetector
cùng với
Phương thức onTouchEvent()
được mô tả ở trên.
Phát hiện tất cả cử chỉ được hỗ trợ
Khi bạn tạo thực thể cho đối tượng GestureDetectorCompat
, một trong
cần thiết là một lớp triển khai
GestureDetector.OnGestureListener
. GestureDetector.OnGestureListener
sẽ thông báo cho người dùng khi
sự kiện chạm cụ thể xảy ra. Để giúp bạn có thể
Đối tượng GestureDetector
để nhận sự kiện, hãy ghi đè khung hiển thị hoặc
phương thức onTouchEvent()
của hoạt động và chuyển mọi sự kiện đã quan sát được
vào thực thể của trình phát hiện.
Trong đoạn mã sau, giá trị trả về là true
từ
on<TouchEvent>
riêng lẻ cho biết rằng
sự kiện chạm đã được xử lý. Giá trị trả về của false
truyền các sự kiện xuống
qua ngăn xếp khung hiển thị cho đến khi thao tác chạm được xử lý thành công.
Nếu chạy đoạn mã sau trong một ứng dụng thử nghiệm, bạn có thể cảm nhận được
được kích hoạt khi bạn tương tác với màn hình cảm ứng và thao tác
nội dung của MotionEvent
dành cho từng sự kiện chạm. Sau đó, bạn sẽ thấy
lượng dữ liệu đang được tạo cho các tương tác đơn giản.
Kotlin
private const val DEBUG_TAG = "Gestures" class MainActivity : Activity(), GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener { private lateinit var mDetector: GestureDetectorCompat // Called when the activity is first created. public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener. mDetector = GestureDetectorCompat(this, this) // Set the gesture detector as the double-tap // listener. mDetector.setOnDoubleTapListener(this) } override fun onTouchEvent(event: MotionEvent): Boolean { return if (mDetector.onTouchEvent(event)) { true } else { super.onTouchEvent(event) } } override fun onDown(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDown: $event") return true } override fun onFling( event1: MotionEvent, event2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { Log.d(DEBUG_TAG, "onFling: $event1 $event2") return true } override fun onLongPress(event: MotionEvent) { Log.d(DEBUG_TAG, "onLongPress: $event") } override fun onScroll( event1: MotionEvent, event2: MotionEvent, distanceX: Float, distanceY: Float ): Boolean { Log.d(DEBUG_TAG, "onScroll: $event1 $event2") return true } override fun onShowPress(event: MotionEvent) { Log.d(DEBUG_TAG, "onShowPress: $event") } override fun onSingleTapUp(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onSingleTapUp: $event") return true } override fun onDoubleTap(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDoubleTap: $event") return true } override fun onDoubleTapEvent(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDoubleTapEvent: $event") return true } override fun onSingleTapConfirmed(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onSingleTapConfirmed: $event") return true } }
Java
public class MainActivity extends Activity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{ private static final String DEBUG_TAG = "Gestures"; private GestureDetectorCompat mDetector; // Called when the activity is first created. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener. mDetector = new GestureDetectorCompat(this,this); // Set the gesture detector as the double-tap // listener. mDetector.setOnDoubleTapListener(this); } @Override public boolean onTouchEvent(MotionEvent event){ if (this.mDetector.onTouchEvent(event)) { return true; } return super.onTouchEvent(event); } @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString()); return true; } @Override public void onLongPress(MotionEvent event) { Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); } @Override public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, float distanceY) { Log.d(DEBUG_TAG, "onScroll: " + event1.toString() + event2.toString()); return true; } @Override public void onShowPress(MotionEvent event) { Log.d(DEBUG_TAG, "onShowPress: " + event.toString()); } @Override public boolean onSingleTapUp(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString()); return true; } @Override public boolean onDoubleTap(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString()); return true; } @Override public boolean onDoubleTapEvent(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString()); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString()); return true; } }
Phát hiện một nhóm nhỏ các cử chỉ được hỗ trợ
Nếu chỉ muốn xử lý một vài cử chỉ, bạn có thể mở rộng
GestureDetector.SimpleOnGestureListener
thay vì triển khai GestureDetector.OnGestureListener
.
GestureDetector.SimpleOnGestureListener
cung cấp
cho tất cả
on<TouchEvent>
phương thức bằng cách trả về
false
cho tất cả các nguyên tắc đó. Thao tác này cho phép bạn chỉ ghi đè các phương thức mà bạn
quan tâm. Ví dụ: đoạn mã sau đây tạo ra một lớp mở rộng
GestureDetector.SimpleOnGestureListener
và ghi đè
onFling()
và onDown()
.
Bạn sử dụng GestureDetector.OnGestureListener
hay
GestureDetector.SimpleOnGestureListener
, tốt nhất là bạn nên
triển khai phương thức onDown()
trả về true
. Chiến dịch này
là do mọi cử chỉ đều bắt đầu bằng thông báo onDown()
. Nếu bạn
trả về false
từ onDown()
, dưới dạng
Theo mặc định, GestureDetector.SimpleOnGestureListener
thực hiện hệ thống
giả định bạn muốn bỏ qua phần còn lại của cử chỉ và các phương pháp khác
GestureDetector.OnGestureListener
không được gọi. Điều này có thể khiến
các sự cố không mong muốn trong ứng dụng của bạn. Chỉ trả lại false
từ
onDown()
nếu bạn thực sự muốn bỏ qua toàn bộ một cử chỉ.
Kotlin
private const val DEBUG_TAG = "Gestures" class MainActivity : Activity() { private lateinit var mDetector: GestureDetectorCompat public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mDetector = GestureDetectorCompat(this, MyGestureListener()) } override fun onTouchEvent(event: MotionEvent): Boolean { mDetector.onTouchEvent(event) return super.onTouchEvent(event) } private class MyGestureListener : GestureDetector.SimpleOnGestureListener() { override fun onDown(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDown: $event") return true } override fun onFling( event1: MotionEvent, event2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { Log.d(DEBUG_TAG, "onFling: $event1 $event2") return true } } }
Java
public class MainActivity extends Activity { private GestureDetectorCompat mDetector; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDetector = new GestureDetectorCompat(this, new MyGestureListener()); } @Override public boolean onTouchEvent(MotionEvent event){ if (this.mDetector.onTouchEvent(event)) { return true; } return super.onTouchEvent(event); } class MyGestureListener extends GestureDetector.SimpleOnGestureListener { private static final String DEBUG_TAG = "Gestures"; @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString()); return true; } } }
Tài nguyên khác
- Tổng quan về sự kiện đầu vào
- Tổng quan về cảm biến
- Tạo thành phần hiển thị tuỳ chỉnh có tính tương tác