OneHandedGestureDefaults

object OneHandedGestureDefaults


Summary

Public functions

suspend Unit
scrollDown(scrollState: ScalingLazyListState, wrapAround: Boolean)

A scroll implementation tailored for use with ScalingLazyListState.

suspend Unit
scrollDown(scrollState: TransformingLazyColumnState, wrapAround: Boolean)

A scroll implementation tailored for use with TransformingLazyColumnState.

suspend Unit
scrollDownToNextItem(
    scrollState: ScalingLazyListState,
    wrapAround: Boolean
)

A scroll implementation tailored for use with ScalingLazyListState.

suspend Unit
scrollDownToNextItem(
    scrollState: TransformingLazyColumnState,
    wrapAround: Boolean
)

A scroll implementation tailored for use with TransformingLazyColumnState.

suspend Unit

Automatically animates the pagerState to the next available page.

Public functions

scrollDown

Added in 1.7.0-alpha05
suspend fun scrollDown(scrollState: ScalingLazyListState, wrapAround: Boolean = true): Unit

A scroll implementation tailored for use with ScalingLazyListState.

This logic handles one-handed gesture by first attempting to scroll the list by half the viewport. If the list cannot scroll further forward, it scrolls back to the start.

Sample demonstrating gesture handling with ScalingLazyListState:

import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberOverscrollEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.EdgeButton
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.onehandedgesture.GestureAction
import androidx.wear.compose.material3.onehandedgesture.GesturePriority
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureDefaults
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureIndicator
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureScrollIndicator
import androidx.wear.compose.material3.onehandedgesture.oneHandedGesture

val backDispatcherOwner = LocalOnBackPressedDispatcherOwner.current
val onClick =
    remember<() -> Unit> { { backDispatcherOwner?.onBackPressedDispatcher?.onBackPressed() } }
val slcState = rememberScalingLazyListState()
val buttonInteractionSource = remember { MutableInteractionSource() }
val slcInteractionSource = remember { MutableInteractionSource() }

ScreenScaffold(
    scrollState = slcState,
    edgeButton = {
        EdgeButton(
            onClick = onClick,
            interactionSource = buttonInteractionSource,
            modifier =
                if (slcState.canScrollForward) {
                    Modifier
                } else {
                    // Apply the one-handed gesture modifier only when the container cannot
                    // scroll further, ensuring the EdgeButton is fully visible and interactive
                    Modifier.oneHandedGesture(
                        action = GestureAction.Primary,
                        priority = GesturePriority.Clickable,
                        interactionSource = buttonInteractionSource,
                        gestureLabel = "close",
                        onGesture = onClick,
                    )
                } then
                    Modifier.scrollable(
                        state = slcState,
                        orientation = Orientation.Vertical,
                        reverseDirection = true,
                        overscrollEffect = rememberOverscrollEffect(),
                    ),
        ) {
            OneHandedGestureIndicator(interactionSource = buttonInteractionSource) {
                Text("Close")
            }
        }
    },
    scrollIndicator = {
        OneHandedGestureScrollIndicator(
            interactionSource = slcInteractionSource,
            state = slcState,
            modifier = Modifier.align(Alignment.CenterEnd),
        )
    },
) { contentPadding ->
    ScalingLazyColumn(
        state = slcState,
        contentPadding = contentPadding,
        modifier =
            Modifier.fillMaxSize()
                .oneHandedGesture(
                    action = GestureAction.Primary,
                    priority = GesturePriority.Scrollable,
                    interactionSource = slcInteractionSource,
                    gestureLabel = "scroll",
                    onGesture = { OneHandedGestureDefaults.scrollDown(slcState) },
                ),
        autoCentering = null,
    ) {
        items(10) { Text("Item $it") }
    }
}
Parameters
scrollState: ScalingLazyListState

The scroll state associated with a scaling lazy column.

wrapAround: Boolean = true

Whether to automatically scroll back to the first item when reaching the end of the content.

scrollDown

Added in 1.7.0-alpha05
suspend fun scrollDown(
    scrollState: TransformingLazyColumnState,
    wrapAround: Boolean = true
): Unit

A scroll implementation tailored for use with TransformingLazyColumnState.

This logic handles one-handed gesture by first attempting to scroll the list by half the viewport. If the list cannot scroll further forward, it scrolls back to the start.

Sample demonstrating gesture handling with TransformingLazyColumnState:

import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberOverscrollEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.EdgeButton
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.onehandedgesture.GestureAction
import androidx.wear.compose.material3.onehandedgesture.GesturePriority
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureDefaults
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureIndicator
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureScrollIndicator
import androidx.wear.compose.material3.onehandedgesture.oneHandedGesture

val backDispatcherOwner = LocalOnBackPressedDispatcherOwner.current
val onClick =
    remember<() -> Unit> { { backDispatcherOwner?.onBackPressedDispatcher?.onBackPressed() } }
val scrollState = rememberTransformingLazyColumnState()
val buttonInteractionSource = remember { MutableInteractionSource() }
val scrollInteractionSource = remember { MutableInteractionSource() }

ScreenScaffold(
    scrollState = scrollState,
    edgeButton = {
        EdgeButton(
            onClick = onClick,
            interactionSource = buttonInteractionSource,
            modifier =
                if (scrollState.canScrollForward) {
                    Modifier
                } else {
                    // Apply the one-handed gesture modifier only when the container cannot
                    // scroll further, ensuring the EdgeButton is fully visible and interactive
                    Modifier.oneHandedGesture(
                        action = GestureAction.Primary,
                        priority = GesturePriority.Clickable,
                        interactionSource = buttonInteractionSource,
                        gestureLabel = "close",
                        onGesture = onClick,
                    )
                } then
                    Modifier.scrollable(
                        state = scrollState,
                        orientation = Orientation.Vertical,
                        reverseDirection = true,
                        overscrollEffect = rememberOverscrollEffect(),
                    ),
        ) {
            OneHandedGestureIndicator(interactionSource = buttonInteractionSource) {
                Text("Close")
            }
        }
    },
    scrollIndicator = {
        OneHandedGestureScrollIndicator(
            interactionSource = scrollInteractionSource,
            state = scrollState,
            modifier = Modifier.align(Alignment.CenterEnd),
        )
    },
) { contentPadding ->
    TransformingLazyColumn(
        state = scrollState,
        contentPadding = contentPadding,
        modifier =
            Modifier.fillMaxSize()
                .oneHandedGesture(
                    action = GestureAction.Primary,
                    priority = GesturePriority.Scrollable,
                    interactionSource = scrollInteractionSource,
                    gestureLabel = "scroll",
                    onGesture = { OneHandedGestureDefaults.scrollDown(scrollState) },
                ),
    ) {
        items(10) { Text("Item $it") }
    }
}
Parameters
scrollState: TransformingLazyColumnState

The scroll state associated with a transforming lazy column.

wrapAround: Boolean = true

Whether to automatically scroll back to the first item when reaching the end of the content.

scrollDownToNextItem

Added in 1.7.0-alpha05
suspend fun scrollDownToNextItem(
    scrollState: ScalingLazyListState,
    wrapAround: Boolean = true
): Unit

A scroll implementation tailored for use with ScalingLazyListState.

This logic handles one-handed gesture by first attempting to scroll to the next item in the list (or scrolling through the current item if it exceeds the viewport size). If the list cannot scroll further forward, it scrolls back to the start.

Sample demonstrating gesture handling with ScalingLazyListState:

import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberOverscrollEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.EdgeButton
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.onehandedgesture.GestureAction
import androidx.wear.compose.material3.onehandedgesture.GesturePriority
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureDefaults
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureIndicator
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureScrollIndicator
import androidx.wear.compose.material3.onehandedgesture.oneHandedGesture

val backDispatcherOwner = LocalOnBackPressedDispatcherOwner.current
val onClick =
    remember<() -> Unit> { { backDispatcherOwner?.onBackPressedDispatcher?.onBackPressed() } }
val slcState = rememberScalingLazyListState()
val buttonInteractionSource = remember { MutableInteractionSource() }
val slcInteractionSource = remember { MutableInteractionSource() }

ScreenScaffold(
    scrollState = slcState,
    edgeButton = {
        EdgeButton(
            onClick = onClick,
            interactionSource = buttonInteractionSource,
            modifier =
                if (slcState.canScrollForward) {
                    Modifier
                } else {
                    // Apply the one-handed gesture modifier only when the container cannot
                    // scroll further, ensuring the EdgeButton is fully visible and interactive
                    Modifier.oneHandedGesture(
                        action = GestureAction.Primary,
                        priority = GesturePriority.Clickable,
                        interactionSource = buttonInteractionSource,
                        gestureLabel = "close",
                        onGesture = onClick,
                    )
                } then
                    Modifier.scrollable(
                        state = slcState,
                        orientation = Orientation.Vertical,
                        reverseDirection = true,
                        overscrollEffect = rememberOverscrollEffect(),
                    ),
        ) {
            OneHandedGestureIndicator(interactionSource = buttonInteractionSource) {
                Text("Close")
            }
        }
    },
    scrollIndicator = {
        OneHandedGestureScrollIndicator(
            interactionSource = slcInteractionSource,
            state = slcState,
            modifier = Modifier.align(Alignment.CenterEnd),
        )
    },
) { contentPadding ->
    ScalingLazyColumn(
        state = slcState,
        contentPadding = contentPadding,
        modifier =
            Modifier.fillMaxSize()
                .oneHandedGesture(
                    action = GestureAction.Primary,
                    priority = GesturePriority.Scrollable,
                    interactionSource = slcInteractionSource,
                    onGesture = { OneHandedGestureDefaults.scrollDownToNextItem(slcState) },
                ),
        autoCentering = null,
    ) {
        items(10) { Text("Item $it") }
    }
}
Parameters
scrollState: ScalingLazyListState

The scroll state associated with a scaling lazy column.

wrapAround: Boolean = true

Whether to automatically scroll back to the first item when reaching the end of the content.

scrollDownToNextItem

Added in 1.7.0-alpha05
suspend fun scrollDownToNextItem(
    scrollState: TransformingLazyColumnState,
    wrapAround: Boolean = true
): Unit

A scroll implementation tailored for use with TransformingLazyColumnState.

This logic handles one-handed gesture by first attempting to scroll to the next item in the list (or scrolling through the current item if it exceeds the viewport size). If the list cannot scroll further forward, it scrolls back to the start.

Sample demonstrating gesture handling with TransformingLazyColumnState:

import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberOverscrollEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.EdgeButton
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.onehandedgesture.GestureAction
import androidx.wear.compose.material3.onehandedgesture.GesturePriority
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureDefaults
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureIndicator
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureScrollIndicator
import androidx.wear.compose.material3.onehandedgesture.oneHandedGesture

val backDispatcherOwner = LocalOnBackPressedDispatcherOwner.current
val onClick =
    remember<() -> Unit> { { backDispatcherOwner?.onBackPressedDispatcher?.onBackPressed() } }
val scrollState = rememberTransformingLazyColumnState()
val buttonInteractionSource = remember { MutableInteractionSource() }
val scrollInteractionSource = remember { MutableInteractionSource() }

ScreenScaffold(
    scrollState = scrollState,
    edgeButton = {
        EdgeButton(
            onClick = onClick,
            interactionSource = buttonInteractionSource,
            modifier =
                if (scrollState.canScrollForward) {
                    Modifier
                } else {
                    // Apply the one-handed gesture modifier only when the container cannot
                    // scroll further, ensuring the EdgeButton is fully visible and interactive
                    Modifier.oneHandedGesture(
                        action = GestureAction.Primary,
                        priority = GesturePriority.Clickable,
                        interactionSource = buttonInteractionSource,
                        gestureLabel = "close",
                        onGesture = onClick,
                    )
                } then
                    Modifier.scrollable(
                        state = scrollState,
                        orientation = Orientation.Vertical,
                        reverseDirection = true,
                        overscrollEffect = rememberOverscrollEffect(),
                    ),
        ) {
            OneHandedGestureIndicator(interactionSource = buttonInteractionSource) {
                Text("Close")
            }
        }
    },
    scrollIndicator = {
        OneHandedGestureScrollIndicator(
            interactionSource = scrollInteractionSource,
            state = scrollState,
            modifier = Modifier.align(Alignment.CenterEnd),
        )
    },
) { contentPadding ->
    TransformingLazyColumn(
        state = scrollState,
        contentPadding = contentPadding,
        modifier =
            Modifier.fillMaxSize()
                .oneHandedGesture(
                    action = GestureAction.Primary,
                    priority = GesturePriority.Scrollable,
                    interactionSource = scrollInteractionSource,
                    onGesture = { OneHandedGestureDefaults.scrollDownToNextItem(scrollState) },
                ),
    ) {
        items(10) { Text("Item $it") }
    }
}
Parameters
scrollState: TransformingLazyColumnState

The scroll state associated with a transforming lazy column.

wrapAround: Boolean = true

Whether to automatically scroll back to the first item when reaching the end of the content.

scrollToNextPage

Added in 1.7.0-alpha05
suspend fun scrollToNextPage(pagerState: PagerState): Unit

Automatically animates the pagerState to the next available page.

This function triggers a smooth scroll transition to the next page index. If the current page is the last page in the pager, the animation will wrap around to the first page (index 0).

Samples demonstrating gesture handling with horizontal and vertical pagers:

import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.pager.HorizontalPager
import androidx.wear.compose.foundation.pager.rememberPagerState
import androidx.wear.compose.material3.AnimatedPage
import androidx.wear.compose.material3.HorizontalPagerScaffold
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.onehandedgesture.GestureAction
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureDefaults
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureHorizontalPageIndicator
import androidx.wear.compose.material3.onehandedgesture.oneHandedGesture

val pagerState = rememberPagerState(pageCount = { 10 })
val interactionSource = remember { MutableInteractionSource() }

HorizontalPagerScaffold(
    pagerState = pagerState,
    pageIndicator = {
        OneHandedGestureHorizontalPageIndicator(
            interactionSource = interactionSource,
            pagerState = pagerState,
        )
    },
) {
    HorizontalPager(
        state = pagerState,
        modifier =
            Modifier.oneHandedGesture(
                action = GestureAction.Primary,
                interactionSource = interactionSource,
                gestureLabel = "scroll to the next page",
            ) {
                OneHandedGestureDefaults.scrollToNextPage(pagerState)
            },
    ) { page ->
        AnimatedPage(pageIndex = page, pagerState = pagerState) {
            ScreenScaffold {
                Column(
                    modifier = Modifier.fillMaxSize(),
                    horizontalAlignment = Alignment.CenterHorizontally,
                    verticalArrangement = Arrangement.Center,
                ) {
                    Text(text = "Page #$page")
                    Spacer(modifier = Modifier.height(8.dp))
                    Text(text = "Swipe left and right")
                }
            }
        }
    }
}
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.pager.VerticalPager
import androidx.wear.compose.foundation.pager.rememberPagerState
import androidx.wear.compose.material3.AnimatedPage
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.VerticalPagerScaffold
import androidx.wear.compose.material3.onehandedgesture.GestureAction
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureDefaults
import androidx.wear.compose.material3.onehandedgesture.OneHandedGestureVerticalPageIndicator
import androidx.wear.compose.material3.onehandedgesture.oneHandedGesture

val pagerState = rememberPagerState(pageCount = { 10 })
val interactionSource = remember { MutableInteractionSource() }

VerticalPagerScaffold(
    pagerState = pagerState,
    pageIndicator = {
        OneHandedGestureVerticalPageIndicator(
            interactionSource = interactionSource,
            pagerState = pagerState,
        )
    },
) {
    VerticalPager(
        state = pagerState,
        modifier =
            Modifier.oneHandedGesture(
                action = GestureAction.Primary,
                interactionSource = interactionSource,
                gestureLabel = "scroll to the next page",
            ) {
                OneHandedGestureDefaults.scrollToNextPage(pagerState)
            },
    ) { page ->
        AnimatedPage(pageIndex = page, pagerState = pagerState) {
            ScreenScaffold {
                Column(
                    modifier = Modifier.fillMaxSize(),
                    horizontalAlignment = Alignment.CenterHorizontally,
                    verticalArrangement = Arrangement.Center,
                ) {
                    Text(text = "Page #$page")
                    Spacer(modifier = Modifier.height(8.dp))
                    Text(text = "Swipe up and down")
                }
            }
        }
    }
}
Parameters
pagerState: PagerState

The state of the pager to be animated.