Start native apps faster with the Composables CLI ->
Compose Modifier

oneHandedGesture

Registers a gesture handler.

OneHandedGestureButtonSample

@Composable
fun OneHandedGestureButtonSample() {
    var label by remember { mutableStateOf("Gesturable Button") }
    val onClick = { label = "Clicked/Gestured" }
    val interactionSource = remember { MutableInteractionSource() }
    val gestureConfig = rememberOneHandedGestureConfiguration(action = GestureAction.Primary)
    val indicatorState = remember { OneHandedGestureIndicatorState() }
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Button(
            onClick = onClick,
            interactionSource = interactionSource,
            modifier =
                Modifier.oneHandedGesture(
                    gestureConfiguration = gestureConfig,
                    interactionSource = interactionSource,
                    onGestureLabel = "activate the button",
                    onGestureAvailable = { indicatorState.isIndicatorActive = true },
                    onGesture = onClick,
                ),
        ) {
            OneHandedGestureIndicator(gestureConfig, indicatorState) { Text(label) }
        }
    }
}

OneHandedGestureHorizontalPagerSample

@Composable
fun OneHandedGestureHorizontalPagerSample() {
    val pagerState = rememberPagerState(pageCount = { 10 })
    val gestureConfig = rememberOneHandedGestureConfiguration(action = GestureAction.Primary)
    val indicatorState = remember { OneHandedGestureIndicatorState() }
    HorizontalPagerScaffold(
        pagerState = pagerState,
        pageIndicator = {
            OneHandedGestureHorizontalPageIndicator(
                gestureConfiguration = gestureConfig,
                indicatorState = indicatorState,
                pagerState = pagerState,
            )
        },
    ) {
        HorizontalPager(
            state = pagerState,
            modifier =
                Modifier.oneHandedGesture(
                    gestureConfiguration = gestureConfig,
                    onGestureLabel = "scroll to the next page",
                    onGestureAvailable = { indicatorState.isIndicatorActive = true },
                ) {
                    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")
                    }
                }
            }
        }
    }
}

OneHandedGestureTransformingLazyColumnSample

@Composable
fun OneHandedGestureTransformingLazyColumnSample() {
    val backDispatcherOwner = LocalOnBackPressedDispatcherOwner.current
    val onClick =
        remember<() -> Unit> { { backDispatcherOwner?.onBackPressedDispatcher?.onBackPressed() } }
    val scrollState = rememberTransformingLazyColumnState()
    val buttonInteractionSource = remember { MutableInteractionSource() }
    val buttonGestureConfig =
        rememberOneHandedGestureConfiguration(
            action = GestureAction.Primary,
            priority = GesturePriority.Clickable,
        )
    val buttonIndicatorState = remember { OneHandedGestureIndicatorState() }
    val scrollGestureConfig =
        rememberOneHandedGestureConfiguration(
            action = GestureAction.Primary,
            priority = GesturePriority.Scrollable,
        )
    val scrollIndicatorState = remember { OneHandedGestureIndicatorState() }
    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(
                            gestureConfiguration = buttonGestureConfig,
                            interactionSource = buttonInteractionSource,
                            onGestureLabel = "close",
                            onGestureAvailable = { buttonIndicatorState.isIndicatorActive = true },
                            onGesture = onClick,
                        )
                    } then
                        Modifier.scrollable(
                            state = scrollState,
                            orientation = Orientation.Vertical,
                            reverseDirection = true,
                            overscrollEffect = rememberOverscrollEffect(),
                        ),
            ) {
                OneHandedGestureIndicator(buttonGestureConfig, buttonIndicatorState) {
                    Text("Close")
                }
            }
        },
        scrollIndicator = {
            OneHandedGestureScrollIndicator(
                gestureConfiguration = scrollGestureConfig,
                indicatorState = scrollIndicatorState,
                scrollState = scrollState,
                modifier = Modifier.align(Alignment.CenterEnd),
            )
        },
    ) { contentPadding ->
        TransformingLazyColumn(
            state = scrollState,
            contentPadding = contentPadding,
            modifier =
                Modifier.fillMaxSize()
                    .oneHandedGesture(
                        gestureConfiguration = scrollGestureConfig,
                        onGestureLabel = "scroll",
                        onGestureAvailable = { scrollIndicatorState.isIndicatorActive = true },
                        onGesture = { OneHandedGestureDefaults.scrollDown(scrollState) },
                    ),
        ) {
            items(10) { Text("Item $it") }
        }
    }
}

OneHandedGestureVerticalPagerSample

@Composable
fun OneHandedGestureVerticalPagerSample() {
    val pagerState = rememberPagerState(pageCount = { 10 })
    val gestureConfig = rememberOneHandedGestureConfiguration(action = GestureAction.Primary)
    val indicatorState = remember { OneHandedGestureIndicatorState() }
    VerticalPagerScaffold(
        pagerState = pagerState,
        pageIndicator = {
            OneHandedGestureVerticalPageIndicator(
                gestureConfiguration = gestureConfig,
                indicatorState = indicatorState,
                pagerState = pagerState,
            )
        },
    ) {
        VerticalPager(
            state = pagerState,
            modifier =
                Modifier.oneHandedGesture(
                    gestureConfiguration = gestureConfig,
                    onGestureLabel = "scroll to the next page",
                    onGestureAvailable = { indicatorState.isIndicatorActive = true },
                ) {
                    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")
                    }
                }
            }
        }
    }
}

Last updated: