https://kotlinlang.org logo
#compose
Title
# compose
a

Archie

09/17/2020, 4:35 PM
I'm really curious whether doing,
Copy code
Crossfade(key) {
    when (it) {
        is CaseA -> ComposableA()
        is CaseB -> ComposableB()
        ....
    }
}
Is just "similar" (effect wise not implmentation wise) as using
AnimatedVisibilty
such as this:
Copy code
AnimatedVisibility(
    visible = key == CaseA,
    exit = ...,
    enter = ...,
    content = content
) {
    ComposableA()
}
AnimatedVisibility(
    visible = key == CaseB,
    exit = ...,
    enter = ...,
    content = content
) {
    ComposableB()
}
I initially though that
Crossfade
was more optimize as in its implementation code, the composable who doesn't hold the current key gets removed...
Copy code
state.items.clear()
        keys.mapTo(state.items) { key ->
            CrossfadeAnimationItem(key) { children ->
                val opacity = animatedOpacity(
                    animation = animation,
                    visible = key == current,
                    onAnimationFinish = {
                        if (key == state.current) {
                            // leave only the current in the list
                            state.items.removeAll { it.key != state.current } // THIS RIGHT HERE!
                            state.invalidate()
                        }
                    }
                )
                Stack(Modifier.drawOpacity(opacity.value)) {
                    children()
                }
            }
        }
But then looking into
AnimatedVisibility
I found this:
Copy code
// If the exit animation has finished, skip the child composable altogether
if (transitionState == AnimStates.Gone) {
    return
}
It looks to me that both
AnimatedVisibility
and
Crossfade
doesn't keep any composable that aren't needed (doesn't match the key). If I am correct about this, then
AnimatedVisibility
would be better for more custom enter and exit animation, where
Crossfade
would only act as a convenience method to use for simple fadeIn fadeOut animation. Did I understand it correctly?
z

Zach Klippenstein (he/him) [MOD]

09/17/2020, 5:28 PM
Makes sense to me. I could also see
Crossfade
allowing custom animations, although at that point it's not a cross fade anymore, but that's just naming. Probably there are different use cases for each where either one would be more readable/show clear intent than the other.
👍 1
t

Timo Drick

09/17/2020, 9:02 PM
Crossfade will support savedInstanceState keeping in the future. But maybe AnimatedVisibility also. So i am not sure. But implementation wise it is a little bit more straight forward to use Crossfade i think. Especially if you have many different items to show.
d

Doris Liu

09/17/2020, 11:14 PM
One feature that is special about Crossfade is that it always keeps the child composable that is entering on top of ones that are exiting, whereas with multiple
AnimatedVisibilty
s, you'll need to be explicit about their z-order if you need the
Crossfade
behavior. This behavior is more obvious when there's overlap between fade in and fade out. 🙂 Aside from that, both of them skip the child composables that have finished exiting/fadd-out.
👍 2
a

Archie

09/18/2020, 4:15 AM
@Doris Liu, is it possible to change the Z ordering with
AnimatedVisibility
so that the composable with the visible key would always be on top?
d

Doris Liu

09/18/2020, 4:56 AM
Yes. You could add a modifier explicitly to
AnimatedVisibility
to change the z-index to non-0 (or the largest among siblings) when visible. That'll put it on top. For example:
Copy code
AnimatedVisibility(visible = enabled.value,
    modifier = Modifier.zIndex(if (enabled.value) 10.0f else 0f)) {...}
❤️ 2
a

Archie

11/04/2020, 6:43 AM
Hi @Doris Liu, I actually dont know if you are the right person to ask but I am trying to swap in/out Scaffold's Appbar depending on the current "Destination" like so...
Copy code
val navController = rememberNavController()

Scaffold(
     topBar = {
          val currentBackStackEntry by navController.currentBackStackEntryAsState()
          val currentRoute = currentBackStackEntry?.arguments?.get(KEY_ROUTE)

          AnimatedVisibility(
              visible = currentRoute == ScreenC.route,
              exit = slideOutVertically(
                  targetOffsetY = { -it },
              ),
              enter = slideInVertically(
                   initialOffsetY = { -it },
              ),
           ) {
               TopAppBar(title = { Text("Sample App") },)
           }

            AnimatedVisibility(
                visible = currentRoute == ScreenB.route,
                exit = slideOutVertically(
                    targetOffsetY = { -it },
                ),
                enter = slideInVertically(
                    initialOffsetY = { -it },
                ),
            ) {
                TopAppBar(
                    modifier = Modifier.height(200.dp),
                    title = { Text("Sample App") },
                )
            }
     },
) {
     val modifier = Modifier.padding(it)
     NavHost(
          navController = navController,
          startDestination = ScreenA.route,
     ) {
          composable(ScreenA.route) {
               MyScreen(modifier, "A", "", "to B") {
                   navController.navigate(ScreenB.route)
               }
          }
          composable(ScreenB.route) {
                MyScreen(modifier, "B",  "", "to C") {
                    navController.navigate(ScreenC.route)
                }
           }
            composable(ScreenC.route) {
                MyScreen(modifier, "C",  "","to A") {
                    navController.navigate(ScreenA.route)
                }
            }
        }
    }
}
But the Scaffold's content doesn't Animate with the AppBar Swapping and instead just jump to the end position. I was wondering if this was intended? If it is, is there any advice you could give to make the animation smoother?
d

Doris Liu

11/04/2020, 7:17 PM
Looks like the screen content didn't animate along with the top bar animation. It is definite not intended. 🙂 It may be the same root cause as https://issuetracker.google.com/issues/172185423 Could you add your use case to that issue, so we can take a closer look?
a

Archie

11/05/2020, 3:55 AM
It seems that it has been marked fixed. I commented my usecase anyway. Thanks @Doris Liu!
Hi @Doris Liu, just wondering about what to expect with Navigation Compose Transition Animation between screens. Will it be similar to the current Fragment Transitions which animates the screen as a whole? Or will there be a possibility to animate individual composables within that screens while transitioning?
d

Doris Liu

12/11/2020, 6:00 PM
Great question! The transition API redesign (going out in alpha09) will make it possible to dynamically declare child animations and attach them to the transition. These child animations can be triggered when state/screen changes. It's possible to animate individual composables using child animations of a
Transition
during the screen change. But we haven't made plans to support that in navigation transition yet. Do you have a specific mock that you are trying to emulate?
😍 2
a

Archie

12/12/2020, 6:11 AM
@Doris Liu Sounds Awesome really excited to try them out. 😍 Thank you very much :D
2 Views