https://kotlinlang.org logo
Title
z

Zoltan Demant

10/05/2021, 5:22 AM
Is it possible to render a scrim using compose with
AnimatedContent
? 🧵👀
Im using AnimatedContent, where the new content uses slideInVertically, and the old uses fadeOut. Id basically like to render a scrim over the old content instead of the fadeOut effect such that the new content can slide "over" it with a shadow like effect. Is this possible?
a

Albert Chang

10/05/2021, 6:06 AM
In the
AnimatedVisibilityScope
, you can use the
transition
property to create your own animation. See here for example.
z

Zoltan Demant

10/05/2021, 6:15 AM
Thanks, Ill try that! 👍🏽
Ive played around with it a fair bit, the transition property helps a lot - but I havent figured out a way to know which content block represents the previous screen. The transitionSpec lends access to
initialState
and
targetState
, is there a way to use the like in the content block as well or should I encode this in the targetState property? Id basically like to animate in/out a scrim over the previous screen whenever Im navigating to the next screen (and never for back navigation).
d

Doris Liu

10/06/2021, 5:24 PM
Could you file a feature request for this? We can make the initialState accessible from the content block. The scrim animation is a great use case and we want to make it easy. 🙂
z

Zoltan Demant

10/07/2021, 3:41 AM
Will do! 👏🏽 Heres a link!
Also, is it possible to acheive the scrim effect using the current animation apis, or any other api for that matter? Id love to have this working, its one of the last things left on my compose revamp! 🙂
d

Doris Liu

10/07/2021, 8:59 PM
Yes. You can get the
initialState
from the Transition if you use the
Transition#AnimatedContent
API. It'd be something like:
val t = updateTransition(..)
t.AnimatedContent(...) {
   // In the content block, remember the current/initialState when the content is first added
   val initialState = remember { t.currentState }
   // Add the scrim animation using AnimatedVisibilityScope#transition
   val scrimAlpha by transition.animatedFloat {
      if (it != Visible && initialState == foo) { 
          0f
      } else {
          if 
      }
   } 
}
z

Zoltan Demant

10/08/2021, 8:29 AM
So glad I asked! Thank you 😊
👏 1
Hey! Sorry but I never managed to quite solve this, would you mind helping me? 🙂 I dont understand how I can detect whether the current
AnimatedContent.content
scope represents the enter or exit content that Im animating to. I think a transition between
Visible -> PostExit
represents exit, but Im not seeing the expected results when following it. I think the logic should be pretty straight-forward. Each state has a size variable, when the old size < new size, the exit content should have a scrim, basically.
d

Doris Liu

12/03/2021, 1:50 AM
You could check the
AnimatedVisbilityScope#transition.targetState
against
PostExit
. What is the result you see?
z

Zoltan Demant

12/03/2021, 8:03 AM
That almost works! The scrim now animates in correctly, but is then hidden just slightly too early - so while the new content is sliding in from the bottom, the old content has a scrim for 90% of the duration, and the last 10% just renders the old content as white (which is my background color) until the new content covers it entirely. After some more digging, I think this is a bug. I havent noticed it simply due to specifying `targetAlpha=0f`; e.g. if I use the code below, Ill see the content fade out and then just abruptly disappear before the transition is complete (again, at about 90% of the duration). I use the same animationSpec for both transitions (spring), and I can verify that the old content is still part of the composition:
DisposableEffect.onDispose
is called exactly when the transition is complete.
initialContentExit = fadeOut(
    targetAlpha = 0.8f
)
d

Doris Liu

12/04/2021, 12:36 AM
The previous content gets removed whenever the exit transition has finished. It does not wait for the whole transition to finish before removing itself.
so while the new content is sliding in from the bottom, the old content has a scrim for 90% of the duration, and the last 10% just renders the old content as white (which is my background color) until the new content covers it entirely.
This sounds to me like the old content was removed after 90% of the total duration, which is likely due to the exit animation finishing. Can you try using a
tween
with the same duration for enter & exit and see if you still observe the same behavior? It's possible that having the old content stick around until both enter & exit transition finish would be more intuitive.
z

Zoltan Demant

12/05/2021, 6:11 AM
Tween makes it work as expected, thank you! Personally Id prefer to see the old content stick around until the whole transition finishes, otherwise spring animations are pretty much no use in situations like this.