Status Update
Comments
tj...@gmail.com <tj...@gmail.com> #2
Can you try with the latest snapshot? Not reproducible for me on androidx-main.
ti...@google.com <ti...@google.com> #3
Ok, after trying a couple more versions, realized this is a duplicate of
From the release notes:
AndroidView's update callback's first invocation will now be defered until the view is attached, instead of running when the composition that introduces the AndroidView is applied. This fixes a bug where the update callback wouldn't be invalidated if a state it read was changed immediately by an effect. (Ie9438,
) b/291094055
Sorry for the confusion!
tj...@gmail.com <tj...@gmail.com> #4
My custom shared element is not in a Modifier.sharedBounds
.
A minimal repro is tough to do in isolation, but I have the full project with the use case on public github and my custom overlay:
Files of note are:
: Custom moveable shared element with use ofMoveableSharedElement.kt
Modifier.approachLayout
. : Where I useAdaptiveContentScope.kt
SharedTransitionLayout
, but also define my own overlay to work around the issue in this bug. : Where I host and manage my "panes" and have the logic for moving them according to navigation state changes. Each "pane" has its ownSavedStateAdaptiveContentState
AnimatedContent
MoveableSharedElement.kt
does a lot of the lookahead target finding and animates its approach, so I end up moving the item in the overlay myself.
The use case for images is in the listings tab in the app, and for video is in the explore tab.
The detailed use case:
-
I have panes, where each pane hosts its own
AnimatedContent
-
Each pane is moveable with
moveableContentOf
-
Most of the time one pane is visible and conventional navigation (push, pop) happen within this pane and is animated with its
AnimatedContent
. -
During a predictive back or drag to dismiss gesture, two panes become visible:
-
The top pane is the current navigation destination. Its is moved to a different Composable slot with a higher z-index to be seen above the previous destination.
-
The bottom pane is the previous navigation destination that will become the current if the top one is popped by committing to the predictive back or drag to dismiss gesture. It is composed in the slot the current navigation destination was just moved out of.
-
This is because the
AnimatedContent
transition in the top pane should not run when the one in the bottom runs to animate the previous destination coming in.
-
-
The moveable shared element between the two destinations should only be rendered in the top pane. It's place in the bottom pane should be an empty box that is visible to the user to communicate that upon commitment, the movable shared element will animate into that space.
-
When the gesture is committed, the movable shared element should neatly animate from the top pane into the empty visible space in the bottom pane.
-
After the animation completes, the system has been reset to the original single pane paradigm.
A few other notes:
-
Since the moveable shared element moves between different panes and therefore different
AnimatedContent
scopes, its animation is not owned by either of theAnimatedContent
panes and is completely self driven. The transitions in either of the panes ending or starting does not have an effect on the moveable shared element animation. The current heuristic I use to stop rendering in the overlay is when both the offset and size animations have reported being idle after starting once, i.e they chase their idle state. -
The above is one of the reasons I don't need a shared element match as the animation is not triggered by either of the transitions in
AnimatedContent
. This is also whyModifier.sharedBounds
is not used. -
I'm trying to replace the need to manage my own graphics layer in
MovableSharedElementData
and also maintain an overlay abstraction with a single call toModifier. renderInSharedTransitionScopeOverlay(sharedElmentData::canDrawInOverlay)
. However the translation in there is conflicting with my approach animations.
tj...@gmail.com <tj...@gmail.com> #5
Fundamentally, I think my issue may be more to do with seeing what I'm trying to achieve as having a distinct mental model and approach that what Modifier.sharedBounds()
solves.
If I can implement the requirements I have using Modifier.sharedBounds()
this issue becomes moot. I just haven't been able to think of a way to achieve it using Modifier.sharedBounds()
.
ti...@google.com <ti...@google.com> #6
Do you also have a PR to show how you used Modifier.renderInSharedTransitionOverlay
modifier?
ti...@google.com <ti...@google.com> #7
tj...@gmail.com <tj...@gmail.com> #8
Yes, the PR is here:
I did try Modifier.sharedElementWithCallerManagedVisibility()
, but I couldn't get the animation to trigger precisely when I wanted it to. I have some quirks about when the animation should trigger with respect to if I'm moving to a pane during predictive back, or just sharing within the same pane.
tj...@gmail.com <tj...@gmail.com> #9
I finally figured out how to use the example you provided for my use case! Thank you so much.
Description
Jetpack Compose version: 1.7.0-beta05 Jetpack Compose component used: Shared elements Kotlin version: 2.0
I have a shared element use case that doesn't quite lend itself well to
Modifier.sharedBounds()
orModifier.sharedElement()
.With both of these Modifiers, the animation is triggered when there is a shared element "match" for incoming and outgoing shared composables within an
AnimatedContent
.In my use case, my component is moved using
movableContentOf
, so it has no "matching" component. This is because the component has expensive hoisted state that is best always attached to it, instead of being detached and reattached to another instance of its composable, or can't be done without a break in continuity. Examples include:ContentScale
, and when moved has anotherContentScale
at its new destination and the content scale has to be animated smoothly.ContentScale
, and when moved has anotherContentScale
at its new destination and the content scale has to be animated smoothly without removing itsExoPlayer
from its surface.i.e, the component is always present, and I self animate the component across the
AnimatedContent
boundaries with a customApproachModifierNode
.This works great at first. The animations work as intended, however it does not render in the overlay with other regular shared elements. I tried elevating it into the overlay with
Modifier.renderInSharedTransitionScopeOverlay()
, and while this works, my custom animations break in the overlay because of the following inRenderInTransitionOverlayNode
:It would be helpful to be able to opt out of the extra translation the
RenderInOverlayNode
applies if I am self animating approaching the lookahead targets.I'm currently working around this by creating my own overlay and rendering there, however, I can't take advantage of the clip paths and other niceties already implemented in the
SharedTransitionScope
.I've attached videos showing the difference between the two.