5

Problem

I want to achieve shared element transition between Activity A and B, and between Activity B and C.

I did everything based on the android transition documentation.

There is no problem between:

  • A => B => back to A

  • A => B and B => C => back to B

But if I do:

  • A => B and B => C => back to B => back to A

The last step will not have any shared element transition (actually not only shared element transition, even there is only fading it could be lost).

I have been looking for solutions everywhere, but it seems everybody only needs A => B (and B => A) shared element transition but doesn't care any more transitions from B => C and back to A.

Example

See an example I created based on android's animation samples, where Activity A = MainActivity, B = DetailActivity, C = DetailDetailActivity. Clicking the button on Activity B will navigate to Activity C.

enter image description here

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
xiaoyu
  • 2,369
  • 2
  • 13
  • 15

2 Answers2

1

Because while executing C => B, it will re-construct a new EnterTransitionCoordinator for B, replacing the old one contains the correct mPendingExitNames which it is important to indicate views need to be transitioned between A and B.

public boolean startExitBackTransition(final Activity activity) {
    ArrayList<String> pendingExitNames = getPendingExitNames(); // here
    if (pendingExitNames == null || mCalledExitCoordinator != null) {
        return false;
    } else {
          // ...
     }
}

The solution seems to be a little bit tricky. You can refer to ThreeActivityTransitionDemo and pay attention to the SharedElementUtils.

  • I am getting an exception `java.lang.NoSuchFieldException: No field mPendingExitNames in class Landroid/app/ActivityTransitionState` – parohy Jan 22 '21 at 10:32
  • Have you already bypassed Android hidden API restrictions? [Restrictions on non-SDK interfaces](https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces) As for my demo provided above, I had imported a dependency `me.weishu:free_reflection:3.0.1` and called `Reflection.unseal(base)` at `ThreeActivityApplication#attachBaseContext` in order to get 'ActivityTransitionState' field in `SharedElementUtils `. – Nemesiss.Lin Jan 23 '21 at 11:10
  • You were right. I did not notice that. After bypassing restrictions it is working. – parohy Feb 05 '21 at 07:22
  • Any luck with solving the issue without reflection? – Woland Mar 17 '21 at 12:15
  • No luck, I had updated repo's README for a brief discussion. Use Fragment instead of Activity can easily do it. – Nemesiss.Lin Mar 18 '21 at 17:47
0

Add this to Activity B

@Override
protected void onStop() {
    if(Build.VERSION.SDK_INT == Build.VERSION_CODES.Q && !isFinishing()){
        new Instrumentation().callActivityOnSaveInstanceState(this, new Bundle());
    }
    super.onStop();
}
seekingStillness
  • 4,833
  • 5
  • 38
  • 68
  • I can't try your solution since I haven't updated my app to target sdk 30 yet, and I'm trying to find a general solution not only working on android 11 – xiaoyu Sep 15 '20 at 11:48
  • ok. does `new Instrumentation().callActivityOnSaveInstanceState(this, new Bundle());` without the version call work on lower sdk? – seekingStillness Sep 15 '20 at 15:47