This repo will show you how to support shared elements animations among multi activities (>= 3) using reflection.
Still no idea (2021.3) and here is my opinion.
If you happen to speak Chinese, you can also refer to 中文版.
Why?
-
Assuming there are 3 activities, A => B => C, (A in the bottom), calling from
supportFinishAfterTransition()
in C, on API 29 platform. -
Results in calling
mActivityTransitionState.startExitBackTransition(this)
, it will construct anExitTransitionCoordinator
which isReturning is TRUE , then fieldmIsBackgroundReady
will be false.mReturnExitCoordinator = new ExitTransitionCoordinator(activity, activity.getWindow(), activity.mEnterTransitionListener, pendingExitNames, null, null, true); public ExitTransitionCoordinator(Activity activity, Window window, SharedElementCallback listener, ArrayList<String> names, ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) { super(window, names, listener, isReturning); viewsReady(mapSharedElements(accepted, mapped)); stripOffscreenViews(); mIsBackgroundReady = !isReturning; // here mActivity = activity; }
-
In B's
performStart()
will callmActivityTransitionState.enterReady(this)
, at that timesharedElementNames
is still containing the shared elements' name. ButsharedElementNames
will just assign tomAllSharedElementNames
inEnterTransitionCoordinator
,mPendingExitNames
won't get the value frommAllSharedElementNames
without receiving messageMSG_ALLOW_RETURN_TRANSITION
. -
In
ExitTransitionCoordinator
, only one piece will send such message:protected void notifyComplete() { if (isReadyToNotify()) { if (!mSharedElementNotified) { mSharedElementNotified = true; delayCancel(); if (!mActivity.isTopOfTask()) { // here mResultReceiver.send(MSG_ALLOW_RETURN_TRANSITION, null); } if (mListener == null) { mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle); notifyExitComplete(); } else { final ResultReceiver resultReceiver = mResultReceiver; final Bundle sharedElementBundle = mSharedElementBundle; mListener.onSharedElementsArrived(mSharedElementNames, mSharedElements, new OnSharedElementsReadyListener() { @Override public void onSharedElementsReady() { resultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, sharedElementBundle); notifyExitComplete(); } }); } } else { notifyExitComplete(); } } }
-
But
isReadyToNotify()
won't returntrue
sincemIsBackgroundReady
is false whileisReturning
is true.protected boolean isReadyToNotify() { return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady; }
-
Therefore, no way to let B's
mEnterTransitionCoordinator.getPendingExitSharedElementNames()
return a non-null value without reflection. SincemActivityTransitionState
is hidden in reflection we also need to bypass it, finally lead to such 'ugly' solution provided in repo.
Really need to share elements among multi 'pages'?
Through sharing elements among activities seems to be tricky, but everything turns good if we use Fragment instead of Activity. I had added another sample for fragment scenario. Here are also some docs and posts written by Google.
https://developer.android.com/guide/fragments/animate#kotlin
https://android-developers.googleblog.com/2018/02/continuous-shared-element-transitions.html
Good luck!