
One-handed gestures offer a convenient and touch-free way for users to interact with their watches, enabling them to perform key actions using only the hand on which the device is worn.
First introduced on Pixel Watch with Wear OS 6.1, one-handed gestures made quick interactions effortless, such as starting and stopping a timer, accepting calls, and controlling media.
Now, with Wear OS 7, we’re expanding this functionality with a new Gestures framework that allows OEMs to map gestures to primary actions and dismissals, and an API to bring gesture control to the developer community.
Starting with the 1.7 beta release of Compose for Wear OS, you can seamlessly integrate gesture control into your Wear Compose apps. To use this release, upgrade your Wear Compose dependency to:
androidx.wear.compose:compose-material3:1.7.0-beta01
Designing for one-handed interaction
The one-handed gestures framework is designed around two primary interaction patterns that allow users to take action without touching the screen:
- Primary action, which on Pixel Watch is mapped to a double-pinch gesture: this action should be mapped to the most important task in a given context. For example, users can perform this gesture to take a photo in a camera app, start/stop a timer, or accept an incoming call.
- Dismiss action, which on Pixel Watch is mapped to a wrist turn gesture: this action is mapped to system back by default and provides an intuitive way to close interruptive screens or get back to the watch face. It may be overridden for specific use cases, such as silencing an incoming phone call.
These gestures are currently available on Pixel Watch 3 and newer, and the Wear OS gesture framework is available to all Wear OS device manufactures to adopt.
Check out our new design guidance for integrating one-handed gestures into your Wear app.
Integrating gestures with Compose on Wear OS
To provide seamless gesture support in Wear OS 7, we are introducing a new Modifier.oneHandedGesture that you can apply to any existing interactive composable to make it gesture-aware.
Implementing gestures with Compose on Wear OS requires these steps:
- Define the gesture configuration. Start by using
rememberOneHandedGestureConfigurationto define the nature of the interaction. This configuration dictates the basic behavior by providing theGestureAction(e.g. tracking a primary pinch or a dismiss wrist flick). - Initialize the indicator state. Depending on your UI component, initialize a specific state object, such as
OneHandedGestureClickIndicatorStatefor buttons orOneHandedGestureScrollIndicatorStatefor scrollable lists. This state is used to coordinate visual feedback between the gesture detection modifier and the visual UI indicators, seamlessly managing visibility, timing, and animations. - Apply Modifier.oneHandedGesture to your interactive component. You’ll pass in your configuration and state, and you’ll provide standard callbacks:
onGestureAvailableto activate the visual hint when the system prepares the gesture, andonGestureto execute your action when the gesture happens.
The following sample shows how those three steps translate into code when configuring an IconButton:
val gestureConfig = rememberOneHandedGestureConfiguration(action = OneHandedGestureAction.Primary)
val indicatorState = remember { OneHandedGestureClickIndicatorState() }
val coroutineScope = rememberCoroutineScope()
OutlinedIconButton(
onClick = onPlayPauseButtonClicked,
modifier = Modifier.touchTargetAwareSize(IconButtonDefaults.LargeButtonSize)
.oneHandedGesture(
gestureConfiguration = gestureConfig,
interactionSource = interactionSource,
onGestureLabel = "play or pause",
onGestureAvailable = {
coroutineScope.launch { indicatorState.showIndicator() }
},
onGesture = onPlayPauseButtonClicked,
),
) {
// button content goes here
// See "Guided discovery with gesture indicators" section of this post for recommendations on adding a gesture indicator.
}
The GestureAction.Primary can also be used to scroll when the content is the end goal of the user journey, or there is a gesture actionable button off screen that the user can scroll to. Some examples include:
- Scrolling through a notification to view the content and/or initiate a reply (available in
TransformingLazyColumnandScalingLazyColumn). - Paging through workout metrics or other content that doesn’t require the user to tap to continue the user journey (available in
HorizontalPagerandVerticalPager).
val scrollGestureConfig = rememberOneHandedGestureConfiguration(action = GestureAction.Primary)
val scrollIndicatorState = remember { OneHandedGestureScrollIndicatorState() }
val coroutineScope = rememberCoroutineScope()
TransformingLazyColumn(
state = scrollState,
contentPadding = contentPadding,
modifier = Modifier
.fillMaxSize()
.oneHandedGesture(
gestureConfiguration = scrollGestureConfig,
onGestureLabel = "scroll",
onGestureAvailable = {
coroutineScope.launch { scrollIndicatorState.showIndicator() }
},
onGesture = { OneHandedGestureDefaults.scrollDown(scrollState) }
)
) {
// list content goes here
// See "Guided discovery with gesture indicators" section of this post for recommendations on adding a gesture indicator.
}
Guided discovery with gesture indicators
To help users learn which gestures are available, gesture indicators work as hints to help discovery about which gestures are available on a screen.
These hints provide animated cues that inform users where they can perform a gesture. The framework manages the cadence and appearance of these hints, ensuring that they are helpful without being intrusive. System settings let users change the cadence to something less frequent if desired.
To integrate with hints, the API provides the following gesture indicator components:
- the OneHandedGestureClickIndicator for components like a
Button - the OneHandedGestureScrollIndicator component for scrolling
- the OneHandedGestureHorizontalPageIndicator for the
HorizontalPager - the OneHandedGestureVerticalPageIndicator for the
VerticalPager
The following example shows how to use the OneHandedGestureClickIndicator for a Button. See another example for using the OneHandedGestureScrollIndicator in our guidance.
val gestureConfig = rememberOneHandedGestureConfiguration(action = GestureAction.Primary)
val indicatorState = remember { OneHandedGestureClickIndicatorState() }
val coroutineScope = rememberCoroutineScope()
OutlinedIconButton(
onClick = onPlayPauseButtonClicked,
modifier = Modifier.touchTargetAwareSize(IconButtonDefaults.LargeButtonSize)
.oneHandedGesture(
gestureConfiguration = gestureConfig,
interactionSource = interactionSource,
onGestureLabel = "play or pause",
onGestureAvailable = {
coroutineScope.launch { indicatorState.showIndicator() }
},
onGesture = onPlayPauseButtonClicked,
),
) {
OneHandedGestureClickIndicator(
gestureConfiguration = gestureConfig,
indicatorState = indicatorState,
) {
val icon = if (playerUiModel.playbackState.isPlaying) Icons.Filled.Pause else Icons.Filled.PlayArrow
Icon(icon, contentDescription = "Play or Pause")
}
}
We are already seeing early adoption of these APIs from partners like Spotify, who are using one-handed gestures to make music control more seamless on the go. By adopting the Modifier.oneHandedGesture into their Wear OS app, Spotify allows users to play or pause their music with the primary gesture action, which on Pixel Watch devices is the double-pinch gesture. This action triggers the same behavior as the physical play/pause button, and the user doesn’t need to touch the screen.
. Bring one-handed gestures to your app
You can begin experimenting with one-handed gestures today in the 1.7 beta release of Compose for Wear OS.
Ensure your app is running on Wear OS 7, which provides the underlying platform support for gesture detection. Check out our new one-handed gestures developer guide to see how you can start building more convenient experiences for your users.

