arkivanov / Decompose

Kotlin Multiplatform lifecycle-aware business logic components (aka BLoCs) with routing (navigation) and pluggable UI (Jetpack Compose, SwiftUI, JS React, etc.)
https://arkivanov.github.io/Decompose
Apache License 2.0
2.25k stars 85 forks source link

How to Disable iOS Swipe-Back Gesture on a Specific Page in a Child Stack Navigation Using Decompose #759

Closed wying111 closed 3 months ago

wying111 commented 3 months ago

I have implemented Predictive Back Gesture on iOS following the code from this page: https://arkivanov.github.io/Decompose/extensions/compose/. My navigation is based on Child Stack. When I navigate from page A to page B, I want to disable the swipe-back gesture on iOS on page B. Is there a way to achieve this?

arkivanov commented 3 months ago

Thanks for the question. I think there is no any nice way of doing this. I will think about it. For now you can try registering a back callback in that component for which you want to disable the back gesture.

class B(
    componentContext: ComponentContext,
    onFinished: () -> Unit,
) : ComponentContext by componentContext {
    init {
        backHandler.register(BackCallback(onBack = onFinished))
    }
}

Then in the parent component you can pass the onFinished callback as follows:

onFinished = navigation::pop
wying111 commented 3 months ago

Thank you. I'll take your advice into consideration.

arkivanov commented 3 months ago

Let's keep this issue open for a while. The use case is valid and I might add an API for it. Thanks!

arkivanov commented 3 months ago

The new version 3.2.0-alpha05 features some improvements to the new experimental animation API released earlier in version 3.2.0-alpha03. It's possible to do something as follows.

@Composable
fun RootContent(component: Root) {
    ChildStack(
        stack = component.stack,
        animation = stackAnimation(
            animator = fade(),
            predictiveBackParams = { stack ->
                if (stack.active.instance is Root.Child.ChildB) {
                    return@stackAnimation null
                }

                PredictiveBackParams(
                    backHandler = component.backHandler,
                    onBack = component::onBack,
                    animatable = ::materialPredictiveBackAnimatable,
                )
            }
        )
    ) {
        when (val child = it.instance) {
            is Root.Child.ChildA -> TODO()
            is Root.Child.ChildB -> TODO()
            is Root.Child.ChildC -> TODO()
        }
    }
}

Don't forget to pass handleBackButton = true when creating childStack.