Fading hero views' children in shared element transition

2.3k views Asked by At

I'm curious how android handles the children of hero views in the shared element transition one can see in Google Keep:

In the standard shared elements transition, on the enter animation, the hero views in the calling activity are instantaneously overlaid with the destination view (at the starting dimensions) before the transition animates changes in the destination view's dimensions to get to their new location.

However, on the return animation, the returning activity's views remain on top of the overlay, and they are the views that are displayed until the animation ends, at which point the destination (calling activity's) hero views snap into place.

This creates a pretty jarring effect if there's any differences in the content of the two hero views -- for example, a textview where the lines wrap differently, or different child views altogether.

Meanwhile, in Google Keep, the shared element transition seems to fade the content views back and forth each way, so this jarring effect is considerably less noticeable. Consequently differences in things like padding or line wrapping are much less problematic.

What's the best way for me to implement this in my own app?

Here is a example:

enter image description here

1

There are 1 answers

1
Ben P. On

My answer is long. And it provides only the general framework to recreate what I saw in your animated image, so you will have to take some time to tweak things yourself to get it perfect.

Code is visible here: https://gist.github.com/zizibaloob/e107fe80afa6873301bf234702d4b2b9

tl;dr: The "shared element" is just the green card/background, so you create the transition using those. Place a gray background behind the green background on the second activity so that the green has something to draw on top of while it's growing. Wrap all of your content in a parent view and animate its alpha to fade in/out.

Full answer

In your image, the "shared element" appears to be the green card on the first screen / the green background of the second screen. On top of that, we add two additional requirements:

  • The gray background of the first activity must be visible during the transition
  • The contents of the card disappear and then fade back in during/after the transition

Let's go through each file and talk about the choices I made to achieve the desired results...

activity_main.xml

This one is really straightforward. I just built up a view hierarchy that vaguely resembled the one in your image. The empty View at the top is a placeholder for a Toolbar, and the Space at the bottom of the card is there just to make it a little larger.

activity_other.xml

The relevant part of this layout is the triple-stack of "parent" views. Each of them serves a purpose:

  • The top-level FrameLayout provides a gray background for the card to "grow" over
  • The middle FrameLayout provides the green background that will be shared between activities
  • The inner LinearLayout wraps everything that we want to have fade in/out, and will be animated by code in the Activity class

MainActivity.java

Another straightforward class. All this Activity does is make the card clickable and set up the transition.

OtherActivity.java

Most of the magic happens here. Within onCreate(), the Toolbar stuff is all standard, so we can skip that. The code inside the if statement is what sets up the fade-in animation (wrapped in an if so it only fades in on first launch). I've also overridden onBackPressed() to reverse the fade animation and to trigger the return transition.

shared_element_transition.xml

All of the rest of the magic is in this file. The <targets> element excludes the status and navigation bars, which makes sure they don't blink during the transition. The various <changeFoo> tags are the actual transition animation that plays.

styles.xml

The only reason that I included this in the Gist at all is the TransitionTheme style. This is applied to OtherActivity in the manifest, and it's what sets our custom transition (from shared_element_transition.xml).

enter image description here