Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support animating an overlay out after returning a result #1066

Merged
merged 10 commits into from
Dec 24, 2023

Conversation

bryanstern
Copy link
Contributor

Currently, if we want an exit animation for an overlay, we must wait for that animated to complete before returning the [Result]. This results in a lot of perceived lag if the [Result] should update the screen it was launched from. While this can be worked around with injecting callbacks or composition locals, those aren't ideal.

This updates ContentWithOverlays to animate an AnimatedOverlay in and out instead of just adding and removing it from composition. I'm open to ways to improve this.

Copy link
Contributor

@chrisbanes chrisbanes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this overall!

Box(modifier) {
content()
key(overlayHostData) { overlayHostData?.let { data -> data.overlay.Content(data::finish) } }
val transition = updateTransition(overlayHost.currentOverlayData, label = null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should keep the original code, and branch when overlay is AnimatedOverlay. Minimises the chances of the experimental API changes causing issues between different Compose versions.

// If transitioning from null to not null, we want to use the targetState. And vice-versa,
// if transitioning from not null to null, we want to use the currentState.
val overlayData by remember {
derivedStateOf { transition.currentState ?: transition.targetState }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The derivedStateOf isn't doing much here. You can remove it and just inline the null coalesce. Also, swapping the content is making me think that an AnimatedContent might be a better fit here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me take another shot using AnimatedContent. I ran into some issues with it in my first draft, but it definitely makes the transition spec calculation nicer...

On the other hand, maybe AnimatedOverlay.AnimatedContent should just observe the Transition's state and animate itself entirely...

@Composable
public abstract fun Transition<EnterExitState>.AnimatedContent(navigator: OverlayNavigator<Result>)

I don't love how we have to change the enter/exit inputs with each state change in the current design.

}
transition.AnimatedVisibility(
visible = { it != null },
modifier = Modifier.fillMaxSize(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, this fillMaxSize() will affect the content layout too. I think it's safer to remove this and let the overlay content define what it wants to do.

* [AnimatedContent] is executed with with [AnimatedVisibilityScope] so that child animations can be
* coordinated with the overlay's animations.
*/
public abstract class AnimatedOverlay<Result : Any>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should mark this as an experimental API. I can see this API evolving.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though the library itself isn't stable yet anyway?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to you here. I still think we can add signal to what APIs are more stable than others?

I don't mind either way though. If you'd rather keep experimental annotations out of here (understandably), all good with me.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I think we're fine without it for now, most of the library would probably fall under that annotation's umbrella if we introduced it heh

@bryanstern
Copy link
Contributor Author

Updated this to use androidx.compose.animation.AnimatedContent. The size transform bits were a little tricky and what initially tripped me up, but I think ultimately works out nicely. The transition calculation is much nicer now. Since this is no longer using experimental animation APIs, I don't see a good reason to branch between the two implementations. In my testing, this works seamlessly for both Overlay types.

One open question is whether AnimatedOverlay be able to specify a SizeTransform. I opted not to include it as is more of an implementation detail of ContentWithOverlays.

Screen_recording_20231222_220709.webm

@chrisbanes
Copy link
Contributor

LGTM! :shipit:

@ZacSweers ZacSweers merged commit d67eac1 into slackhq:main Dec 24, 2023
2 of 3 checks passed
@ZacSweers
Copy link
Collaborator

Thanks!

final override fun Content(navigator: OverlayNavigator<Result>) {
AnimatedContent(
targetState = Unit,
transitionSpec = { EnterTransition.None togetherWith ExitTransition.None },

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should be using enterTransition and exitTransition here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh good catch #1090

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants