Sử dụng cử chỉ cổ tay trên Wear
Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang
Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Các cử chỉ cổ tay có thể cho phép bạn tương tác nhanh chóng bằng một tay với ứng dụng khi không tiện dùng màn hình cảm ứng.
Ví dụ: người dùng có thể cuộn qua các thông báo bằng một tay trong khi vẫn cầm một cốc nước bằng tay còn lại. Các trường hợp sử dụng khác đối với cử chỉ cổ tay gồm có:
- Trong ứng dụng chạy bộ, thao tác di chuyển qua các màn hình dọc hiển thị số bước đã chạy, thời gian đã trôi qua và tốc độ hiện tại
- Trong ứng dụng du lịch, thao tác di chuyển qua thông tin chuyến bay và cổng bay
- Trong ứng dụng tin tức, thao tác di chuyển qua các bài viết
Để xem các cử chỉ cổ tay trên thiết bị đồng hồ, hãy nhớ bật cử chỉ bằng cách chọn Settings > Advanced features > Gestures > Wrist Gestures On (Cài đặt > Tính năng nâng cao > Cử chỉ > Bật cử chỉ cổ tay). Sau đó, hãy hoàn tất phần hướng dẫn về Cử chỉ trên đồng hồ bằng cách chọn Launch Tutorial (Mở hướng dẫn).
Lưu ý: Lắc cổ tay là cử chỉ huỷ hoặc quay lại trên toàn hệ thống và cử chỉ này không được cung cấp cho các ứng dụng để tuỳ chỉnh.
Bạn có thể dùng cử chỉ cổ tay theo những cách sau như mô tả trong hướng dẫn này:
Mỗi cử chỉ cổ tay được liên kết với một hằng số int
từ lớp KeyEvent
, như minh hoạ trong bảng sau:
Sử dụng bố cục cong để hỗ trợ cử chỉ cổ tay
Lớp
WearableRecyclerView
cung cấp bố cục kiểu đường cong cho các danh sách và tự động hỗ trợ các cử chỉ cổ tay. Lớp này có các thao tác được định sẵn cho các lần xuất hiện cử chỉ cổ tay khi khung hiển thị có tâm điểm. Để biết thông tin về cách sử dụng lớp WearableRecyclerView
, hãy xem bài viết Tạo danh sách trên Wear OS. Ngoài ra, hãy xem phần Các phương pháp hay nhất trong hướng dẫn này.
Lưu ý: Lớp WearableRecyclerView
thay thế cho một lớp tương tự đã ngừng sử dụng trong Thư viện hỗ trợ thiết bị đeo.
Ngay cả khi dùng WearableRecyclerView
, bạn vẫn nên sử dụng các hằng số của lớp KeyEvent
. Bạn có thể ghi đè các thao tác được định sẵn bằng cách phân lớp con WearableRecyclerView
và triển khai lại lệnh gọi lại onKeyDown()
. Bạn có thể tắt hoàn toàn hành vi này bằng cách sử dụng setEnableGestureNavigation(false)
.
Để biết thêm thông tin, hãy xem bài viết Xử lý thao tác trên bàn phím.
Trực tiếp sử dụng các sự kiện chính
Bạn có thể sử dụng các sự kiện chính bên ngoài
WearableRecyclerView
nhằm kích hoạt thao tác mới để phản hồi các sự kiện cử chỉ. Quan trọng là các sự kiện cử chỉ này được nhận dạng khi thiết bị ở chế độ đang hoạt động và được phân phối theo cách tương tự như mọi sự kiện chính.
Một lớp liên quan đến hoạt động tương tác của người dùng (chẳng hạn như View
hoặc Activity
) giúp triển khai
KeyEvent.Callback
có thể theo dõi các sự kiện chính liên quan đến cử chỉ cổ tay như được liệt kê với bất kỳ sự kiện chính nào khác. Khung Android gọi View
hoặc Activity
tập trung vào các sự kiện chính. Đối với cử chỉ, lệnh gọi lại phương thức onKeyDown()
sẽ được gọi khi xuất hiện cử chỉ.
Ví dụ: ứng dụng có thể ghi đè các thao tác được định sẵn trong View
hoặc Activity
giúp triển khai KeyEvent.Callback
như sau:
Kotlin
class GesturesActivity : Activity() {
/* KeyEvent.Callback */
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
return when (keyCode) {
KeyEvent.KEYCODE_NAVIGATE_NEXT ->
// Do something that advances a user View to the next item in an ordered list.
moveToNextItem()
KeyEvent.KEYCODE_NAVIGATE_PREVIOUS ->
// Do something that advances a user View to the previous item in an ordered list.
moveToPreviousItem()
else -> {
// If you did not handle it, let it be handled by the next possible element as determined
// by the Activity.
super.onKeyDown(keyCode, event)
}
}
}
/** Shows the next item in the custom list. */
private fun moveToNextItem(): Boolean {
...
// Return true if handled successfully, otherwise return false.
return false
}
/** Shows the previous item in the custom list. */
private fun moveToPreviousItem(): Boolean {
...
// Return true if handled successfully, otherwise return false.
return false
}
}
Java
public final class GesturesActivity extends Activity {
@Override /* KeyEvent.Callback */
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_NAVIGATE_NEXT:
// Do something that advances a user View to the next item in an ordered list.
return moveToNextItem();
case KeyEvent.KEYCODE_NAVIGATE_PREVIOUS:
// Do something that advances a user View to the previous item in an ordered list.
return moveToPreviousItem();
}
// If you did not handle it, let it be handled by the next possible element as determined by the Activity.
return super.onKeyDown(keyCode, event);
}
/** Shows the next item in the custom list. */
private boolean moveToNextItem() {
boolean handled = false;
...
// Return true if handled successfully, otherwise return false.
return handled;
}
/** Shows the previous item in the custom list. */
private boolean moveToPreviousItem() {
boolean handled = false;
...
// Return true if handled successfully, otherwise return false.
return handled;
}
}
Các phương pháp hay nhất
- Xem lại các trang
KeyEvent
và
KeyEvent.Callback
để cung cấp các sự kiện chính cho View
và Activity
.
- Duy trì khả năng cung cấp hướng mang tính nhất quán: sử dụng cử chỉ "xoay cổ tay ra ngoài" cho mục tiếp theo và "xoay cổ tay vào trong" cho mục trước.
- Tạo một cử chỉ chạm song song.
- Cung cấp phản hồi bằng hình ảnh.
- Không sử dụng mã phím để triển khai chức năng khác thường với phần còn lại của hệ thống. Ví dụ: không sử dụng
KEYCODE_NAVIGATE_NEXT
để huỷ một thao tác hoặc di chuyển trục trái, phải bằng cách xoay cổ tay.
- Đừng chặn các sự kiện chính trên các thành phần không thuộc giao diện người dùng, chẳng hạn như các khung hiển thị bị che khuất hoặc bị che khuất một phần. Việc này cũng tương tự như đối với mọi sự kiện chính.
- Đừng diễn giải lại các cử chỉ xoay cổ tay liên tục thành cử chỉ mới lạ của riêng bạn.
Cử chỉ này có thể xung đột với cử chỉ "lắc cổ tay" của hệ thống.
Để nhận được các sự kiện chính liên quan đến cử chỉ, khung hiển thị phải có tâm điểm; hãy xem
View.setFocusable()
.
Vì các cử chỉ được coi là sự kiện chính, nên các cử chỉ sẽ kích hoạt quá trình chuyển đổi ra khỏi "chế độ cảm ứng" giúp thực hiện những việc không mong muốn. Vì người dùng có thể thay thế giữa việc sử dụng thao tác chạm và cử chỉ, nên có thể cần đến phương thức
View::setFocusableInTouchmode()
. Trong một số trường hợp, bạn cũng cần sử dụng setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS)
để khi tâm điểm thay đổi sau khi chuyển thành hoặc chuyển từ chế độ cảm ứng, thì khung hiển thị dự định của bạn sẽ được lấy làm tâm điểm.
- Hãy dùng
requestFocus()
và clearFocus()
một cách thận trọng:
- Khi gọi
requestFocus()
, hãy đảm bảo khung hiển thị đó thích hợp để lấy làm tâm điểm. Nếu khung hiển thị nằm ngoài màn hình hoặc bị một khung hiển thị khác che phủ, thì bạn có thể thấy bất ngờ khi các cử chỉ kích hoạt lệnh gọi lại.
- Phương thức
clearFocus()
sẽ bắt đầu một lượt tìm kiếm tâm điểm để tìm một khung hiển thị khác phù hợp. Tuỳ thuộc vào hệ phân cấp khung hiển thị, lượt tìm kiếm này có thể cần đến các phép tính không hề nhỏ. Điều này cũng có thể kết thúc bằng việc gán tâm điểm cho một khung hiển thị bạn không mong muốn.
Trước tiên, các sự kiện chính sẽ được phân phối đến khung hiển thị có tâm điểm trong hệ phân cấp khung hiển thị. Nếu khung hiển thị có tâm điểm không xử lý sự kiện, nói cách khác là khung hiển thị trả về false
, thì sự kiện đó sẽ không được gửi đến khung hiển thị gốc, ngay cả khi khung hiển thị đó nhận tâm điểm và có
KeyListener
. Thay vào đó, sự kiện này được phân phối đến hoạt động hiện tại có tâm điểm là hệ phân cấp khung hiển thị.
Do đó, cần phải nắm rõ mọi sự kiện ở cấp cao hơn rồi truyền các mã liên quan xuống.
Ngoài ra, bạn có thể phân lớp con đối với hoạt động và ghi đè phương thức
dispatchKeyEvent(KeyEvent event)
để chặn các khoá khi cần thiết hoặc xử lý các khoá đó khi chúng không được xử lý ở các lớp thấp hơn.
Nội dung và mã mẫu trên trang này phải tuân thủ các giấy phép như mô tả trong phần Giấy phép nội dung. Java và OpenJDK là nhãn hiệu hoặc nhãn hiệu đã đăng ký của Oracle và/hoặc đơn vị liên kết của Oracle.
Cập nhật lần gần đây nhất: 2025-07-26 UTC.
[[["Dễ hiểu","easyToUnderstand","thumb-up"],["Giúp tôi giải quyết được vấn đề","solvedMyProblem","thumb-up"],["Khác","otherUp","thumb-up"]],[["Thiếu thông tin tôi cần","missingTheInformationINeed","thumb-down"],["Quá phức tạp/quá nhiều bước","tooComplicatedTooManySteps","thumb-down"],["Đã lỗi thời","outOfDate","thumb-down"],["Vấn đề về bản dịch","translationIssue","thumb-down"],["Vấn đề về mẫu/mã","samplesCodeIssue","thumb-down"],["Khác","otherDown","thumb-down"]],["Cập nhật lần gần đây nhất: 2025-07-26 UTC."],[],[],null,["# Use wrist gestures on Wear\n\nWrist gestures can enable quick, one-handed interactions with your app\nwhen a touch screen is inconvenient.\n\n\nFor example, a user can scroll\nthrough notifications with one hand while holding a cup of water with the\nother. Other use cases for wrist gestures include the following:\n\n- In a jogging app, navigating through vertical screens that show the steps taken, time elapsed, and current pace\n- In a travel app, scrolling through flight and gate information\n- In a news app, scrolling through articles\n\n\nTo review the [wrist gestures](https://support.google.com/androidwear/answer/6312406) on a watch\ndevice, confirm that gestures are\nturned on by selecting **Settings \\\u003e Advanced features \\\u003e Gestures \\\u003e Wrist Gestures\nOn** . Then complete the\nGestures tutorial on the watch by selecting **Launch Tutorial**.\n\n\n**Note:** Shaking the wrist is the system-wide back or undo gesture\nand is not available for apps to customize.\n\n\nWrist gestures can be used in the following ways, as described in this guide:\n\n- With a [curved layout](#using_wrv), which has predefined gesture actions\n- By using [key events directly](#using_key_events) to define new user actions\n\n\nEach wrist gesture is mapped to an `int` constant from the\n[KeyEvent](/reference/android/view/KeyEvent)\nclass, as shown in the following table:\n\n| Gesture | KeyEvent | Description |\n|-----------------|-------------------------------------------------------------------------------------------|------------------------------------------|\n| Flick wrist out | [`KEYCODE_NAVIGATE_NEXT`](/reference/android/view/KeyEvent#KEYCODE_NAVIGATE_NEXT) | This key code goes to the next item. |\n| Flick wrist in | [`KEYCODE_NAVIGATE_PREVIOUS`](/reference/android/view/KeyEvent#KEYCODE_NAVIGATE_PREVIOUS) | This key code goes to the previous item. |\n\nUse a curved layout to support wrist gestures\n---------------------------------------------\n\n\nThe [WearableRecyclerView](/reference/androidx/wear/widget/WearableRecyclerView) class provides a curved\nlayout for lists and automatically supports\nwrist gestures. The class has predefined actions for occurrences of\nwrist gestures when the view has focus. For information about using\nthe `WearableRecyclerView` class, see [Create lists on Wear OS](/training/wearables/ui/lists). Also, see the\n[Best practices](#best_practices) section of this guide.\n\n\n**Note:** The `WearableRecyclerView` class replaces a similar,\n[deprecated](/training/wearables/ui/wear-ui-library#deprecations) class in the Wearable Support Library.\n\n\nEven if you use a `WearableRecyclerView`, you might want to use\nconstants from the [KeyEvent](/reference/android/view/KeyEvent)\nclass. The predefined actions can be overridden by subclassing the\n`WearableRecyclerView` and re-implementing the\n`onKeyDown()` callback. The behavior can be disabled entirely\nby using [`setEnableGestureNavigation(false)`](/reference/android/support/wearable/view/WearableListView#setEnableGestureNavigation(boolean)).\nFor more information, see\n[Handle keyboard actions](/training/keyboard-input/commands).\n\nUse key events directly\n-----------------------\n\n\nYou can use key events outside of a [WearableRecyclerView](/reference/androidx/wear/widget/WearableRecyclerView) to trigger new actions in response to gesture\nevents. Importantly, these gesture events are recognized when a device is in\nactive mode, and they are delivered in the same way as all key events.\n\n\nA class that relates to user interaction, such as a `View` or an\n`Activity`, and that implements\n[KeyEvent.Callback](/reference/android/view/KeyEvent.Callback) can listen to key events that relate to\nwrist gestures just as it can listed to any other key event. The Android framework\ncalls the `View` or `Activity` that has\nfocus with the key events. For gestures, the `onKeyDown()`\nmethod callback is called when gestures occur.\n\n\nAs an example, an app can override predefined actions in a `View`\nor `Activity` that implements `KeyEvent.Callback` as follows: \n\n### Kotlin\n\n```kotlin\nclass GesturesActivity : Activity() {\n\n /* KeyEvent.Callback */\n override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {\n return when (keyCode) {\n KeyEvent.KEYCODE_NAVIGATE_NEXT -\u003e\n // Do something that advances a user View to the next item in an ordered list.\n moveToNextItem()\n KeyEvent.KEYCODE_NAVIGATE_PREVIOUS -\u003e\n // Do something that advances a user View to the previous item in an ordered list.\n moveToPreviousItem()\n else -\u003e {\n // If you did not handle it, let it be handled by the next possible element as determined\n // by the Activity.\n super.onKeyDown(keyCode, event)\n }\n }\n }\n\n /** Shows the next item in the custom list. */\n private fun moveToNextItem(): Boolean {\n ...\n // Return true if handled successfully, otherwise return false.\n return false\n }\n\n /** Shows the previous item in the custom list. */\n private fun moveToPreviousItem(): Boolean {\n ...\n // Return true if handled successfully, otherwise return false.\n return false\n }\n}\n```\n\n### Java\n\n```java\npublic final class GesturesActivity extends Activity {\n\n @Override /* KeyEvent.Callback */\n public boolean onKeyDown(int keyCode, KeyEvent event) {\n switch (keyCode) {\n case KeyEvent.KEYCODE_NAVIGATE_NEXT:\n // Do something that advances a user View to the next item in an ordered list.\n return moveToNextItem();\n case KeyEvent.KEYCODE_NAVIGATE_PREVIOUS:\n // Do something that advances a user View to the previous item in an ordered list.\n return moveToPreviousItem();\n }\n // If you did not handle it, let it be handled by the next possible element as determined by the Activity.\n return super.onKeyDown(keyCode, event);\n }\n\n /** Shows the next item in the custom list. */\n private boolean moveToNextItem() {\n boolean handled = false;\n ...\n // Return true if handled successfully, otherwise return false.\n return handled;\n }\n\n /** Shows the previous item in the custom list. */\n private boolean moveToPreviousItem() {\n boolean handled = false;\n ...\n // Return true if handled successfully, otherwise return false.\n return handled;\n }\n}\n```\n\nBest practices\n--------------\n\n- Review the [KeyEvent](/reference/android/view/KeyEvent) and [KeyEvent.Callback](/reference/android/view/KeyEvent.Callback) pages for the delivery of key events to your `View` and `Activity`.\n- Keep a consistent directional affordance: use \"flick wrist out\" for next and \"flick wrist in\" for previous.\n- Have a touch parallel for a gesture.\n- Provide visual feedback.\n- Don't use a keycode to implement functionality that would be counterintuitive to the rest of the system. For example, don't use `KEYCODE_NAVIGATE_NEXT` to cancel an action or to navigate the left-right axis with flicks.\n- Don't intercept the key events on elements that are not part of the user interface, such as views that are offscreen or partially covered. This is the same as for any key event.\n- Don't reinterpret repeated flick gestures into your own novel gesture. This might conflict with the system's \"shaking the wrist\" gesture.\n- For a view to receive gesture key events, it must have [focus](/reference/android/view/View#attr_android:focusable); see [`\n View.setFocusable()`](/reference/android/view/View#setFocusable(boolean)).\n\n Because gestures are treated as key events,\n they trigger a transition out of \"touch mode\" that might do unexpected\n things. Since users may alternate between using touch and\n gestures, the [`\n View::setFocusableInTouchmode()`](/reference/android/view/View#setFocusableInTouchMode(boolean)) method could be necessary. In some\n cases, it also could be necessary to use\n `setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS)` so\n that when focus changes after a change to or from touch mode, your\n intended view gets the focus.\n- Use [requestFocus()](/reference/android/view/View#requestFocus()) and [clearFocus()](/reference/android/view/View#clearFocus()) carefully:\n - When calling `requestFocus()`, make sure it's appropriate for the view to have focus. If the view is offscreen or is covered by another view, surprises can occur when gestures trigger callbacks.\n - The `clearFocus()` method initiates a focus search to find another suitable view. Depending on the view hierarchy, this search might require nontrivial computation. It can also end up assigning focus to a view you don't expect to receive focus.\n- Key events are delivered first to the view with focus in the view\n hierarchy. If the focused view does not handle the event---in other words, it returns\n `false`---the event is not delivered to the parent view, even\n if it can receive focus and has a [`\n KeyListener`](/reference/android/text/method/KeyListener). Rather, the event is delivered to the current activity\n holding the view hierarchy with focus.\n\n Therefore, it might be necessary to\n catch all events at the higher level, then pass relevant codes down.\n Alternatively, you might subclass the activity and override the\n [dispatchKeyEvent(KeyEvent event)](/reference/android/app/Activity#dispatchKeyEvent(android.view.KeyEvent)) method to intercept keys\n when necessary or handle them when they are not handled at\n lower layers."]]