Wear에서 손목 동작 사용
컬렉션을 사용해 정리하기
내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.
터치스크린이 불편할 때 손목 동작을 사용하면 한 손으로 빠르게 앱과 상호작용할 수 있습니다.
예를 들어 사용자가 한 손에 물컵을 들고 다른 한 손으로 알림을 스크롤할 수 있습니다. 손목 동작의 다른 사용 사례는 다음과 같습니다.
- 조깅 앱에서 걸음 수, 경과 시간, 현재 속도를 보여주는 세로 화면 탐색
- 여행 앱에서 항공편 및 게이트 정보 스크롤
- 뉴스 앱에서 기사 스크롤
시계 기기에서 손목 동작을 검토하려면 설정 > 고급 기능 > 동작 > 손목 동작 사용을 선택하여 동작이 켜져 있는지 확인합니다. 그런 다음 튜토리얼 시작을 선택하여 시계에서 동작 튜토리얼을 완료합니다.
참고: 손목 흔들기는 시스템 전체 뒤로 또는 실행취소 동작이므로 앱에서 맞춤설정할 수 없습니다.
손목 동작은 이 가이드에 설명된 대로 다음과 같은 방식으로 사용할 수 있습니다.
각 손목 동작은 다음 표에 나와 있는 것처럼 KeyEvent
클래스의 int
상수로 매핑됩니다.
손목 동작을 지원하는 곡선형 레이아웃 사용
WearableRecyclerView
클래스는 목록에 곡선형 레이아웃을 제공하고 손목 동작을 자동으로 지원합니다. 이 클래스에는 뷰에 포커스가 있을 때 손목 동작이 발생하는 경우를 위한 미리 정의된 동작이 있습니다. WearableRecyclerView
클래스 사용에 관한 자세한 내용은 Wear OS에서 목록 만들기를 참고하세요. 또한 이 가이드의 권장사항 섹션을 참고하세요.
참고: WearableRecyclerView
클래스는 웨어러블 지원 라이브러리에서 지원 중단된 유사 클래스를 대체합니다.
WearableRecyclerView
를 사용하더라도 KeyEvent
클래스의 상수를 사용하고 싶을 수 있습니다. 미리 정의된 작업은 WearableRecyclerView
를 서브클래스로 분류하고 onKeyDown()
콜백을 다시 구현하여 재정의할 수 있습니다. 동작은 setEnableGestureNavigation(false)
를 사용하여 완전히 중지할 수 있습니다.
자세한 내용은
키보드 작업 처리를 참고하세요.
키 이벤트 직접 사용
WearableRecyclerView
이외의 키 이벤트를 사용하여 동작 이벤트에 대한 응답으로 새 작업을 트리거할 수 있습니다. 무엇보다도 이러한 동작 이벤트는 기기가 활성 모드일 때 인식되며 모든 키 이벤트와 동일한 방식으로 전달됩니다.
View
또는 Activity
와 같은 사용자 상호작용과 관련되고
KeyEvent.Callback
을 구현하는 클래스는 다른 키 이벤트에 나열할 수 있는 것처럼 손목 동작과 관련된 키 이벤트를 수신 대기할 수 있습니다. Android 프레임워크는 키 이벤트에 포커스가 있는 View
또는 Activity
를 호출합니다. 동작의 경우 동작이 발생할 때 onKeyDown()
메서드 콜백이 호출됩니다.
예를 들어 앱은 다음과 같이 KeyEvent.Callback
을 구현하는 View
또는 Activity
에서 사전 정의된 작업을 재정의할 수 있습니다.
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;
}
}
권장사항
- 키 이벤트를
View
와 Activity
에 전달하는 방법에 관해서는 KeyEvent
및
KeyEvent.Callback
페이지를 검토합니다.
- 일관된 방향 어포던스를 유지합니다. 다음 항목으로 이동하려면 '손목을 바깥쪽으로 휙 돌리기', 이전 항목으로 이동하려면 '손목을 안쪽으로 휙 돌리기'를 사용합니다.
- 동작과 일관적인 터치를 사용합니다.
- 시각적 피드백을 제공합니다.
- 시스템의 나머지에 직관적이지 않을 수 있는 기능을 구현하기 위해 키 코드를 사용하지 않습니다. 예를 들어 작업을 취소하거나 획 돌리기로 좌우 축을 이동하는 데
KEYCODE_NAVIGATE_NEXT
를 사용하지 마세요.
- 사용자 인터페이스의 일부가 아닌 요소(예: 화면을 벗어나거나 부분적으로 덮인 뷰)에서 키 이벤트를 가로채지 않습니다. 이는 모든 키 이벤트에 동일합니다.
- 반복되는 획 돌리기 동작을 자체적인 새로운 동작으로 재해석하지 않습니다.
이는 시스템의 '손목 흔들기' 동작과 충돌할 수도 있습니다.
동작 키 이벤트를 수신할 뷰에는
포커스가 있어야 합니다.
View.setFocusable()
을 참고하세요.
동작은 키 이벤트로 처리되기 때문에 '터치 모드'에서 전환을 트리거하여 예기치 않은 작업으로 이어질 수 있습니다. 사용자는 터치와 동작을 번갈아 사용할 수 있으므로
View::setFocusableInTouchmode()
메서드가 필요할 수 있습니다. 경우에 따라, '터치 모드'를 오갈 때 포커스가 변경될 경우 의도한 뷰에 포커스가 오도록 하려면 setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS)
를 사용해야 할 수 있습니다.
- 신중하게
requestFocus()
및 clearFocus()
를 사용합니다.requestFocus()
를 호출할 때 뷰에 포커스가 있는 것이 적절한지 확인합니다. 뷰가 화면을 벗어나거나 다른 뷰로 덮여 있는 경우 동작이 콜백을 트리거하면 사용자가 놀랄 수 있습니다.
clearFocus()
메서드는 다른 적절한 뷰를 찾기 위해 포커스 검색을 시작합니다. 뷰 계층 구조에 따라, 검색에 상당한 계산이 필요할 수 있습니다. 또한 포커스를 받을 것으로 예상하지 않은 뷰에 포커스가 할당될 수도 있습니다.
키 이벤트는 뷰 계층 구조에서 포커스가 있는 뷰로 먼저 전달됩니다. 포커스가 놓인 뷰가 이벤트를 처리하지 않으면(즉, false
를 반환함) 포커스를 받을 수 있고
KeyListener
를 보유하고 있더라도 이벤트가 상위 뷰에 전달되지 않습니다. 오히려 포커스가 있는 뷰 계층 구조를 보유한 현재 활동으로 이벤트가 전달됩니다.
따라서 상위 수준의 모든 이벤트를 포착한 다음 관련 코드를 전달해야 할 수 있습니다.
또는 활동을 서브클래스로 분류하고
dispatchKeyEvent(KeyEvent event)
메서드를 재정의하여 필요한 경우 키를 가로채거나 하위 레이어에서 처리되지 않는 키를 처리할 수도 있습니다.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-07-26(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 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."]]