Bài học này mô tả cách theo dõi chuyển động trong các sự kiện chạm.
Một mô hình
onTouchEvent()
được kích hoạt bằng một
ACTION_MOVE
sự kiện
bất cứ khi nào vị trí tiếp xúc chạm, áp suất hoặc kích thước hiện tại thay đổi. Như
được mô tả trong Phát hiện các cử chỉ phổ biến, tất cả
Những sự kiện này được ghi lại trong
tham số MotionEvent
của
onTouchEvent()
.
Vì thao tác chạm bằng ngón tay không phải lúc nào cũng là hình thức tương tác chính xác nhất, việc phát hiện các sự kiện chạm thường dựa trên chuyển động hơn là tiếp xúc đơn giản. Để giúp ứng dụng phân biệt giữa các cử chỉ dựa trên chuyển động (chẳng hạn như vuốt) và cử chỉ không chuyển động (chẳng hạn như một lần nhấn), Android bao gồm khái niệm Touch slop. Khoảng cách chạm đề cập đến khoảng cách tính bằng pixel mà người dùng có thể chạm di chuyển trước khi cử chỉ được hiểu là cử chỉ dựa trên chuyển động. Để biết thêm thông tin về chủ đề này, hãy xem Quản lý sự kiện chạm trong ViewGroup.
Có một số cách theo dõi chuyển động trong một cử chỉ, tuỳ thuộc vào nhu cầu của ứng dụng. Sau đây là các ví dụ:
- Vị trí bắt đầu và kết thúc của con trỏ, chẳng hạn như di chuyển trên màn hình vật từ điểm A đến điểm B.
- Hướng di chuyển của con trỏ, như được xác định bởi X và Y toạ độ.
- Lịch sử. Bạn có thể tìm kích thước của nhật ký cử chỉ bằng cách gọi hàm
MotionEvent
phương thứcgetHistorySize()
. Sau đó, bạn có thể biết được vị trí, kích thước, thời gian và áp lực của mỗi sự kiện lịch sử bằng cách sử dụng sự kiện chuyển độnggetHistorical<Value>
. Nhật ký rất hữu ích khi hiển thị dấu vết ngón tay của người dùng, chẳng hạn như đối với thao tác vẽ bằng cách chạm. Hãy xem tài liệu tham khảoMotionEvent
để biết thông tin chi tiết. - Vận tốc của con trỏ khi con trỏ di chuyển trên màn hình cảm ứng.
Hãy tham khảo các tài nguyên liên quan sau:
- 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
Theo dõi vận tốc
Bạn có thể có một cử chỉ dựa trên chuyển động dựa trên khoảng cách hoặc hướng
con trỏ di chuyển. Tuy nhiên, tốc độ thường là yếu tố quyết định trong việc theo dõi
đặc điểm của một cử chỉ hoặc quyết định liệu cử chỉ có xảy ra hay không. Để thực hiện
tính toán vận tốc dễ dàng hơn, Android cung cấp
Lớp VelocityTracker
.
VelocityTracker
giúp bạn theo dõi tốc độ của các sự kiện chạm. Thông tin này hữu ích
dành cho các cử chỉ trong đó tốc độ là một phần của tiêu chí cho cử chỉ, chẳng hạn như
một cử chỉ hất.
Dưới đây là ví dụ minh hoạ mục đích của các phương thức trong
API VelocityTracker
:
Kotlin
private const val DEBUG_TAG = "Velocity" class MainActivity : Activity() { private var mVelocityTracker: VelocityTracker? = null override fun onTouchEvent(event: MotionEvent): Boolean { when (event.actionMasked) { MotionEvent.ACTION_DOWN -> { // Reset the velocity tracker back to its initial state. mVelocityTracker?.clear() // If necessary, retrieve a new VelocityTracker object to watch // the velocity of a motion. mVelocityTracker = mVelocityTracker ?: VelocityTracker.obtain() // Add a user's movement to the tracker. mVelocityTracker?.addMovement(event) } MotionEvent.ACTION_MOVE -> { mVelocityTracker?.apply { val pointerId: Int = event.getPointerId(event.actionIndex) addMovement(event) // When you want to determine the velocity, call // computeCurrentVelocity(). Then, call getXVelocity() and // getYVelocity() to retrieve the velocity for each pointer // ID. computeCurrentVelocity(1000) // Log velocity of pixels per second. It's best practice to // use VelocityTrackerCompat where possible. Log.d("", "X velocity: ${getXVelocity(pointerId)}") Log.d("", "Y velocity: ${getYVelocity(pointerId)}") } } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { // Return a VelocityTracker object back to be re-used by others. mVelocityTracker?.recycle() mVelocityTracker = null } } return true } }
Java
public class MainActivity extends Activity { private static final String DEBUG_TAG = "Velocity"; ... private VelocityTracker mVelocityTracker = null; @Override public boolean onTouchEvent(MotionEvent event) { int index = event.getActionIndex(); int action = event.getActionMasked(); int pointerId = event.getPointerId(index); switch(action) { case MotionEvent.ACTION_DOWN: if(mVelocityTracker == null) { // Retrieve a new VelocityTracker object to watch the // velocity of a motion. mVelocityTracker = VelocityTracker.obtain(); } else { // Reset the velocity tracker back to its initial state. mVelocityTracker.clear(); } // Add a user's movement to the tracker. mVelocityTracker.addMovement(event); break; case MotionEvent.ACTION_MOVE: mVelocityTracker.addMovement(event); // When you want to determine the velocity, call // computeCurrentVelocity(). Then call getXVelocity() and // getYVelocity() to retrieve the velocity for each pointer ID. mVelocityTracker.computeCurrentVelocity(1000); // Log velocity of pixels per second. It's best practice to use // VelocityTrackerCompat where possible. Log.d("", "X velocity: " + mVelocityTracker.getXVelocity(pointerId)); Log.d("", "Y velocity: " + mVelocityTracker.getYVelocity(pointerId)); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: // Return a VelocityTracker object back to be re-used by others. mVelocityTracker.recycle(); break; } return true; } }
Sử dụng tính năng chụp con trỏ
Một số ứng dụng, chẳng hạn như trò chơi, máy tính từ xa và ứng dụng ảo hoá, được hưởng lợi quyền kiểm soát con trỏ chuột. Chụp con trỏ là một tính năng có sẵn trong Android 8.0 (API cấp 26) trở lên, cung cấp khả năng kiểm soát này bằng cách phân phối tất cả sự kiện chuột đến chế độ xem tập trung trong ứng dụng của bạn.
Yêu cầu chụp con trỏ
Một khung hiển thị trong ứng dụng của bạn chỉ có thể yêu cầu chụp con trỏ khi hệ phân cấp khung hiển thị
chứa tiêu điểm. Vì lý do này, hãy yêu cầu chụp con trỏ khi có
hành động cụ thể của người dùng trên chế độ xem, chẳng hạn như trong khi
onClick()
hoặc trong
onWindowFocusChanged()
trình xử lý sự kiện của hoạt động.
Để yêu cầu thu thập con trỏ, hãy gọi phương thức
requestPointerCapture()
trên khung hiển thị. Ví dụ về mã sau đây cho thấy cách yêu cầu con trỏ
thu thập khi người dùng nhấp vào một chế độ xem:
Kotlin
fun onClick(view: View) { view.requestPointerCapture() }
Java
@Override public void onClick(View view) { view.requestPointerCapture(); }
Sau khi yêu cầu chụp con trỏ thành công, Android sẽ gọi
onPointerCaptureChange(true)
.
Hệ thống đưa các sự kiện chuột đến chế độ xem tập trung trong ứng dụng của bạn miễn là
hệ phân cấp khung hiển thị đó ở cùng hệ phân cấp khung hiển thị với khung hiển thị đã yêu cầu chụp. Lý do khác
các ứng dụng ngừng nhận sự kiện chuột cho đến khi chụp ảnh được nhả ra, bao gồm
ACTION_OUTSIDE
các sự kiện. Android phân phối các sự kiện con trỏ từ các nguồn không phải chuột dưới dạng
bình thường nhưng con trỏ chuột không còn hiển thị.
Xử lý các sự kiện con trỏ đã ghi
Sau khi khung hiển thị nhận thành công ảnh chụp con trỏ, Android sẽ phân phối sự kiện chuột. Khung hiển thị tập trung có thể xử lý các sự kiện bằng cách thực hiện một trong các nhiệm vụ sau:
- Nếu bạn đang dùng khung hiển thị tuỳ chỉnh, hãy ghi đè
onCapturedPointerEvent(MotionEvent)
. - Nếu không, hãy đăng ký
OnCapturedPointerListener
.
Ví dụ về mã sau đây cho thấy cách triển khai
onCapturedPointerEvent(MotionEvent)
:
Kotlin
override fun onCapturedPointerEvent(motionEvent: MotionEvent): Boolean { // Get the coordinates required by your app. val verticalOffset: Float = motionEvent.y // Use the coordinates to update your view and return true if the event is // successfully processed. return true }
Java
@Override public boolean onCapturedPointerEvent(MotionEvent motionEvent) { // Get the coordinates required by your app. float verticalOffset = motionEvent.getY(); // Use the coordinates to update your view and return true if the event is // successfully processed. return true; }
Ví dụ về mã sau đây biểu thị cách đăng ký
OnCapturedPointerListener
:
Kotlin
myView.setOnCapturedPointerListener { view, motionEvent -> // Get the coordinates required by your app. val horizontalOffset: Float = motionEvent.x // Use the coordinates to update your view and return true if the event is // successfully processed. true }
Java
myView.setOnCapturedPointerListener(new View.OnCapturedPointerListener() { @Override public boolean onCapturedPointer (View view, MotionEvent motionEvent) { // Get the coordinates required by your app. float horizontalOffset = motionEvent.getX(); // Use the coordinates to update your view and return true if the event is // successfully processed. return true; } });
Cho dù bạn sử dụng khung hiển thị tuỳ chỉnh hay đăng ký một trình nghe, thì khung hiển thị đó vẫn nhận được một
MotionEvent
có toạ độ con trỏ chỉ định chuyển động tương đối, chẳng hạn như X
hay còn gọi là delta Y, tương tự như toạ độ do thiết bị bi xoay cung cấp. Bạn có thể
để truy xuất toạ độ bằng cách sử dụng
getX()
và
getY()
.
Thả chụp con trỏ
Thành phần hiển thị trong ứng dụng có thể giải phóng hoạt động chụp con trỏ bằng cách gọi
releasePointerCapture()
!
như trong đoạn mã ví dụ sau:
Kotlin
override fun onClick(view: View) { view.releasePointerCapture() }
Java
@Override public void onClick(View view) { view.releasePointerCapture(); }
Hệ thống có thể gỡ ảnh ra khỏi chế độ xem mà không cần bạn thể hiện rõ ràng
gọi releasePointerCapture()
, thường là do hệ phân cấp khung hiển thị
chứa khung hiển thị yêu cầu ảnh chụp sẽ mất tiêu điểm.