บทเรียนนี้จะอธิบายวิธีติดตามการเคลื่อนไหวในเหตุการณ์การสัมผัส
ใหม่
onTouchEvent()
จะทริกเกอร์ด้วย
ACTION_MOVE
กิจกรรม
เมื่อใดก็ตามที่ตำแหน่งของการสัมผัส ความกดดัน หรือขนาดในปัจจุบันมีการเปลี่ยนแปลง อาส
ตามที่อธิบายไว้ในตรวจหาท่าทางสัมผัสทั่วไป
กิจกรรมเหล่านี้จะบันทึกใน
พารามิเตอร์ MotionEvent
ของ
onTouchEvent()
เนื่องจากการแตะที่ใช้นิ้วไม่ใช่รูปแบบการโต้ตอบที่ถูกต้องแม่นยำที่สุดเสมอไป การตรวจจับกิจกรรมการสัมผัสมักอิงตามการเคลื่อนไหวมากกว่าการสัมผัสง่ายๆ เพื่อช่วยให้แอปแยกความแตกต่างระหว่างท่าทางสัมผัสตามการเคลื่อนไหว (เช่น การปัด) กับ ท่าทางสัมผัสที่ไม่มีการเคลื่อนไหว (เช่น การแตะครั้งเดียว) Android มีแนวคิด การแตะ Slop Touch Slop หมายถึงระยะทางเป็นพิกเซลที่การแตะของผู้ใช้ทำได้ เดินไปมาก่อนที่จะตีความว่าเป็นท่าทางสัมผัสตามการเคลื่อนไหว สำหรับข้อมูลเพิ่มเติม เกี่ยวกับหัวข้อนี้ โปรดดูจัดการกิจกรรมการสัมผัสใน ViewGroup
การติดตามการเคลื่อนไหวในท่าทางสัมผัสทำได้หลายวิธี ขึ้นอยู่กับ ตามความต้องการของแอปพลิเคชันของคุณ ตัวอย่างมีดังต่อไปนี้
- ตำแหน่งเริ่มต้นและสิ้นสุดของเคอร์เซอร์ เช่น การย้ายบนหน้าจอ จากจุด A ไปยังจุด B
- ทิศทางที่ตัวชี้กำลังเดินทางไป ตามที่กำหนดโดย X และ Y พิกัด
- ประวัติ คุณสามารถดูขนาดประวัติของท่าทางสัมผัสได้โดยเรียกใช้
MotionEvent
วิธีgetHistorySize()
จากนั้นคุณสามารถดูตำแหน่ง ขนาด เวลา และแรงกดของ เหตุการณ์ทางประวัติศาสตร์โดยใช้เหตุการณ์การเคลื่อนไหวgetHistorical<Value>
ประวัติมีประโยชน์เมื่อแสดงภาพรอยนิ้วของผู้ใช้ เช่น สำหรับการแตะภาพวาด ดูรายละเอียดในข้อมูลอ้างอิงMotionEvent
- ความเร็วของตัวชี้เมื่อเคลื่อนที่ผ่านหน้าจอสัมผัส
โปรดดูแหล่งข้อมูลที่เกี่ยวข้องต่อไปนี้
ติดตามความเร็ว
คุณใช้ท่าทางสัมผัสที่อิงตามการเคลื่อนไหวได้โดยอิงตามระยะทางหรือทิศทาง
ที่ตัวชี้เคลื่อนที่ อย่างไรก็ตาม อัตราความเร็วมักเป็นปัจจัยที่กำหนดในการติดตาม
ลักษณะของท่าทางสัมผัสหรือการตัดสินว่าท่าทางสัมผัสนั้นๆ เกิดขึ้นหรือไม่ เพื่อให้
การคำนวณอัตราความเร็วที่ง่ายขึ้น Android มอบ
VelocityTracker
VelocityTracker
ช่วยคุณติดตามความเร็วของกิจกรรมการสัมผัส มีประโยชน์
สำหรับท่าทางสัมผัสที่มีความเร็วเป็นส่วนหนึ่งของเกณฑ์สำหรับท่าทางสัมผัส เช่น
การสะบัด
ต่อไปนี้เป็นตัวอย่างที่แสดงให้เห็นถึงวัตถุประสงค์ของวิธีการใน
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; } }
ใช้การจับภาพตัวชี้
แอปบางแอป เช่น เกมและ Remote Desktop และไคลเอ็นต์ระบบเสมือนจริง จะได้รับประโยชน์ ควบคุมเคอร์เซอร์เมาส์ได้ การจับภาพเคอร์เซอร์เป็นฟีเจอร์ พร้อมใช้งานใน Android 8.0 (API ระดับ 26) ขึ้นไปที่ให้การควบคุมนี้โดย การส่งเหตุการณ์เมาส์ทั้งหมดไปยังมุมมองที่โฟกัสในแอปของคุณ
ขอการจับภาพเคอร์เซอร์
มุมมองในแอปของคุณจะสามารถขอเคอร์เซอร์ที่จับภาพได้ต่อเมื่อลำดับชั้นการดูที่
ที่มีโฟกัส ด้วยเหตุนี้ ให้ส่งคำขอจับภาพเคอร์เซอร์
การดำเนินการที่เฉพาะเจาะจงของผู้ใช้ในข้อมูลพร็อพเพอร์ตี้ เช่น ระหว่าง
onClick()
หรือใน
onWindowFocusChanged()
เครื่องจัดการเหตุการณ์ของกิจกรรม
หากต้องการขอจับภาพตัวชี้ ให้เรียกเมธอด
requestPointerCapture()
ในมุมมอง ตัวอย่างโค้ดต่อไปนี้แสดงวิธีขอตัวชี้
บันทึกเมื่อผู้ใช้คลิกการดู
Kotlin
fun onClick(view: View) { view.requestPointerCapture() }
Java
@Override public void onClick(View view) { view.requestPointerCapture(); }
เมื่อส่งคำขอเพื่อบันทึกเคอร์เซอร์สำเร็จแล้ว Android จะเรียกใช้
onPointerCaptureChange(true)
ระบบจะส่งเหตุการณ์เมาส์ไปยังมุมมองที่โฟกัสในแอปของคุณตราบใดที่
อยู่ในลำดับชั้นการแสดงผลเดียวกันกับมุมมองที่ขอการจับภาพ อื่นๆ
แอปจะหยุดรับกิจกรรมเกี่ยวกับเมาส์จนกว่าจะเปิดตัวการจับภาพ ซึ่งรวมถึง
ACTION_OUTSIDE
กิจกรรม Android จะแสดงเหตุการณ์ตัวชี้จากแหล่งที่มาอื่นๆ ที่ไม่ใช่เมาส์ในรูปแบบ
ปกติ แต่มองไม่เห็นเคอร์เซอร์เมาส์แล้ว
จัดการเหตุการณ์ตัวชี้ที่บันทึกไว้
เมื่อข้อมูลพร็อพเพอร์ตี้ได้รับข้อมูลที่บันทึกเคอร์เซอร์แล้ว Android จะแสดง เหตุการณ์ของเมาส์ มุมมองที่โฟกัสสามารถจัดการเหตุการณ์ต่างๆ ได้โดยดำเนินการหนึ่งใน งานต่อไปนี้:
- หากคุณใช้มุมมองที่กำหนดเอง ให้ลบล้าง
onCapturedPointerEvent(MotionEvent)
- หรือไม่เช่นนั้น ให้ลงทะเบียน
OnCapturedPointerListener
ตัวอย่างโค้ดต่อไปนี้แสดงวิธีติดตั้ง
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; }
ตัวอย่างโค้ดต่อไปนี้แสดงวิธีลงทะเบียน
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; } });
ไม่ว่าคุณจะใช้มุมมองที่กำหนดเองหรือลงทะเบียน Listener มุมมองของคุณจะได้รับ
MotionEvent
พร้อมพิกัดของตัวชี้ที่ระบุการเคลื่อนที่แบบสัมพัทธ์ เช่น X
หรือเดลต้า Y ซึ่งคล้ายกับพิกัดที่ได้รับจากอุปกรณ์แทร็กบอล คุณสามารถ
เรียกดูพิกัดโดยใช้
getX()
และ
getY()
การจับภาพตัวชี้การเผยแพร่
มุมมองในแอปสามารถเปิดตัวการจับภาพตัวชี้ด้วยการเรียก
releasePointerCapture()
ดังที่แสดงในตัวอย่างโค้ดต่อไปนี้
Kotlin
override fun onClick(view: View) { view.releasePointerCapture() }
Java
@Override public void onClick(View view) { view.releasePointerCapture(); }
ระบบอาจนำการจับภาพออกจากมุมมองโดยที่คุณไม่ต้องขอ
การเรียก releasePointerCapture()
โดยทั่วไปเนื่องจากลำดับชั้นการแสดงผล
ซึ่งมีข้อมูลพร็อพเพอร์ตี้ที่คำขอจับภาพสูญเสียการโฟกัส