OneHandedGestureDefaults

object OneHandedGestureDefaults


Summary

Public functions

suspend Unit

A scroll implementation tailored for use with ScalingLazyListState.

suspend Unit

A scroll implementation tailored for use with TransformingLazyColumnState.

suspend Unit

A scroll implementation tailored for use with ScalingLazyListState.

suspend Unit

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-alpha04
suspend fun scrollDown(scrollState: ScalingLazyListState): 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,
                        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.scrollDown(slcState) },
                ),
        autoCentering = null,
    ) {
        items(10) { Text("Item $it") }
    }
}
Parameters
scrollState: ScalingLazyListState

The scroll state associated with a scaling lazy column.

scrollDown

Added in 1.7.0-alpha04
suspend fun scrollDown(scrollState: TransformingLazyColumnState): 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,
                        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.scrollDown(scrollState) },
                ),
    ) {
        items(10) { Text("Item $it") }
    }
}
Parameters
scrollState: TransformingLazyColumnState

The scroll state associated with a transforming lazy column.

scrollToNextItem

Added in 1.7.0-alpha04
suspend fun scrollToNextItem(scrollState: ScalingLazyListState): 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,
                        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.scrollToNextItem(slcState) },
                ),
        autoCentering = null,
    ) {
        items(10) { Text("Item $it") }
    }
}
Parameters
scrollState: ScalingLazyListState

The scroll state associated with a scaling lazy column.

scrollToNextItem

Added in 1.7.0-alpha04
suspend fun scrollToNextItem(scrollState: TransformingLazyColumnState): 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,
                        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.scrollToNextItem(scrollState) },
                ),
    ) {
        items(10) { Text("Item $it") }
    }
}
Parameters
scrollState: TransformingLazyColumnState

The scroll state associated with a transforming lazy column.

scrollToNextPage

Added in 1.7.0-alpha04
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,
            ) {
                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,
            ) {
                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.