<@UHAJKUSTU> The predictive back gesture on Androi...
# decompose
v
@Arkadii Ivanov The predictive back gesture on Android, does not feel the same as whats shown in Android’s Docs The rate at which the ui scales down, seems much lower in Decompose’s implementation Any way to customize it?
It does not look like the actual back nav animation in Android 14 On my device, its like this
On Reddit App, the animation is the default Android 14 one, as seen in the recording
It also looks transparent in between the animation if any of my screen does not have a background color applied
a
Please see the docs: https://arkivanov.github.io/Decompose/extensions/compose/#predictive-back-gesture There are material specs for the predictive back navigation, and Decompose resembles that spec: https://developer.android.com/design/ui/mobile/guides/patterns/predictive-back You can create your own animation, though.
For instance, if you want an animation similar to the one in Android 14 (the one in the Android Docs), you can try the following:
Copy code
internal fun CountersContent(component: CountersComponent, modifier: Modifier = Modifier) {
    Children(
        stack = component.childStack,
        modifier = modifier,
        animation = predictiveBackAnimation(
            backHandler = component.backHandler,
            fallbackAnimation = stackAnimation(fade() + scale()),
            selector = { initialBackEvent, _, _ ->
                predictiveBackAnimatable(
                    initialBackEvent = initialBackEvent,
                    exitModifier = { progress, edge -> Modifier.exitModifier(progress = progress, edge = edge) },
                    enterModifier = { progress, _ -> Modifier.enterModifier(progress = progress) },
                )
            },
            onBack = component::onBackClicked,
        ),
    ) {
        ...
    }
}

private fun Modifier.exitModifier(progress: Float, edge: BackEvent.SwipeEdge): Modifier =
    scale(1F - progress * 0.25F)
        .absoluteOffset(
            x = when (edge) {
                BackEvent.SwipeEdge.LEFT -> 32.dp * progress
                BackEvent.SwipeEdge.RIGHT -> (-32).dp * progress
                BackEvent.SwipeEdge.UNKNOWN -> 0.dp
            },
        )
        .alpha(((1F - progress) * 2F).coerceAtMost(1F))
        .clip(RoundedCornerShape(size = 64.dp * progress))

private fun Modifier.enterModifier(progress: Float): Modifier =
    drawWithContent {
        drawContent()
        drawRect(color = Color(red = 0F, green = 0F, blue = 0F, alpha = (1F - progress) / 4F))
    }
v
Thanks a lot, I'll give it a try
a
The animation from the system settings can be implemented manually by implementing the
PersistentBackAnimatable
interface and returning it from the
selector
lambda. You can refer to the default animatable implementation for reference.
v
Will check that out For iOS, I'm using the same implementation as shown in the docs Any way to customize it so we can swipe back from middle of the screen (like slack), it now works only from the edge?
a
You can try implementing your own PredictiveBackGestureOverlay, but it may be taking precedence over horizontally scrolling widgets.
u
How does native ios manage this? I mean the precedence between horizontally scrolling widgets and back swipe?
a
Correct me if I'm wrong, but native iOS only supports back gesture on the start (e.g. left edge on LTR layout and right edge on RTL). You can try adapting the PredictiveBackGestureOverlay and see how it works.
u
You are right. But it's a bit more sensitive. Will modify the overlay and report my findings.
u
Thank you so much. Will take a look
👍 1
@Arkadii Ivanov I have managed to increase the edge detection to entire screen However, the precedence seems to be overridden in terms of horizontal scroll vs back swipe Going by documentation
PointerEventPass.Initial
seems to be correct precedence. Another aspect is first back swipe, right after coming to a new screen is sometimes dropped. Perhaps because of
If requireUnconsumed is true and the first down is consumed in the PointerEventPass.Main pass, that gesture is ignored
How can I customise this to give scroll events the precedence and not drop gesture event.
a
PointerEventPass.Initial
seems to be correct precedence
I thought Initial means that the overlay will have (and use) the opportunity to intercept touch events before they reach scrollable widgets. I would try using another
PointerEventPass
. Also maybe try placing the overlay under the content, not above.
u
I have tried both
Main
and
Final
. Do not seem to have an effect
a
That's surprising, as I remember I selected Initial on purpose.
u
Yeah neither of them with combination of
requireUnconsumed
produce the desired effect. What if even strange is at times the first attempt to back swipe is completely ignored
Placing overlay under the content completely blocks swipe events
a
Yeah, I guess surfaces may block touch events, etc.
u
From what the documentation states
Main
should allow descendants to handle the touch before ancestors.
a
Yes. But I don't have much experience with this.
u
Hmmm
a
I think I was able to implement it by placing the overlay Box under the content (inside an outer Box), and without Surfaces for screens. This worked when there are widgets intercepting swipe gestures in all directions.
With the default overlay placement,
pointerInput
messes with the screen content that also handles touch events.
So I would only enable this behaviour on screens that do not have widgets swipable from start to end (end to start should be ok, like Reply in Telegram).
u
I got it. Perhaps the reason why internal screens in major apps dont have horizontally swipable items
a
Exactly
u
This seems more like a UX problem rather than a tech one. Hopefully this discussion would be fruitful for the community if someone treads this kind of a requirement with KMP
a
It feels like HorizontalPager (which I'm testing on) doesn't consume touch events, and they are also being handled by the overlay (with the default placement, not under the content). So HorizontalPager is being swiped and at the same time the entire screen is being dragged.
u
This is the exact problem I am running into
What would the right way to ignore drag back swipe while horizontal scrolling items is being interacted with?
a
I don't see any ways currently, apart from placing the overlay underneath
Maybe worth asking in #compose channel about pointerInput
139 Views