AnimatedContent(targetState) animates between two versions of some content, by default fading the old one out while the new one fades in and animating the size between them. BookNest uses it twice: the button's label switches between "Add to cart" and "In your cart", and the cart badge counts up and down:
BadgedBox(badge = { Badge { AnimatedContent(cartCount) { Text("$it") } } }) {Use the lambda's parameter, not cartCount: during the transition an old and a new copy exist, and each must draw its own value. transitionSpec can slide numbers up or down instead.
A shared element transition makes one element appear to travel between screens, like the cover growing from a catalog row into the detail header. Wrap the NavHost in SharedTransitionLayout, give both covers the same key, and pass the AnimatedVisibilityScope that each composable { } destination provides:
CoilCover(book, Modifier.sharedElement(rememberSharedContentState("cover-${book.id}"),
animatedVisibilityScope = visibility))
...
CoilCover(book, Modifier.sharedElement(rememberSharedContentState("cover-${book.id}"),
animatedVisibilityScope = visibility).size(160.dp, 240.dp))During navigation Compose 234 measures both elements, draws the shared one in an overlay above both screens, and animates its bounds from the 80 by 120 dp row to the 160 by 240 dp header. BookNest still opts in with @OptIn(ExperimentalSharedTransitionApi::class). Keys must be unique per screen, hence the book ID; sharedBounds is the variant for two different-looking elements that share a container.