Completely prevent Activity transitions from interfering with shared element transitions:
On the exiting activity, call getWindow().setExitTransition(null);
On the entering activity, call getWindow().setEnterTransition(null);
From https://mcmap.net/q/168937/-blinking-screen-on-image-transition-between-activities
I suspect this may have side effects, but don't know for sure. It is dead simple and works though.
Prevent specific elements from blinking:
I started with Alex Lockwood's answer and did a fair bit of experimentation to try to get it working. The core of it is correct, although I didn't need the code he suggests for the receiving Activity, but I ran into some problems by calling it in a Fragment (instead of an Activity) and by setting a toolbar as the action bar.
Oh, the Fragment thing? I saw a lot of comments that trying to retrieve references to the status bar and navigation bar were null. The same thing happened to me as well, until I realized I wouldn't find those in the Fragment's layout... they were above that level. Hence, the code below to get the decor view from the Activity and search that. Then I found them with no problem.
In the end, I developed this utility method:
public static Bundle transitionOptions(Activity activity, int transitionViewResId, int transitionNameResId) {
if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
return null;
}
View decorView = activity.getWindow().getDecorView();
View statusBar = decorView.findViewById(android.R.id.statusBarBackground);
View navigationBar = decorView.findViewById(android.R.id.navigationBarBackground);
View appBarLayout = decorView.findViewById(**R.id.appbarlayout**);
View transitionView = decorView.findViewById(transitionViewResId);
String transitionName = activity.getString(transitionNameResId);
List<Pair<View, String>> pairs = new ArrayList<>();
pairs.add(Pair.create(statusBar, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME));
pairs.add(Pair.create(navigationBar, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME));
if (appBarLayout != null) {
pairs.add(Pair.create(appBarLayout, activity.getString(**R.string.transition_appbarlayout**)));
}
pairs.add(Pair.create(transitionView, transitionName));
//noinspection unchecked - we're not worried about the "unchecked" conversion of List<Pair> to Pair[] here
return ActivityOptionsCompat.makeSceneTransitionAnimation(activity, pairs.toArray(new Pair[pairs.size()]))
.toBundle();
}
Note R.string.transition_appbarlayout and R.id.appbarlayout. These IDs are arbitrary, as long as they match what your code uses. In my XML, I layout the custom action bar like so (edited down to the essentials):
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
android:id="**@+id/appbarlayout**"
android:transitionName="**@string/transition_appbarlayout**">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"/>
</android.support.design.widget.AppBarLayout>
If you don't use a Toolbar like this, that part can be removed from the utility method.
Then you would call it in your Fragment like so:
startActivity(intent, UIUtils.transitionOptions(getActivity(),
R.id.**my_view**,
R.string.**transition_my_view**));
Using whatever values you want, as long as it matches your XML.
This prevents the status bar, the tool bar and the navigation bar (back / home / recent apps buttons) from flashing during the transition. The rest of the Activity transition is normal.
In my case, our app theme has a android:windowBackground
of blue. This causes a blue flash in the transition, which is quite frustrating. But rather than make a change that affects the entire app like that, for now I am going with the first, quick and dirty option.