How do I prevent the status bar and navigation bar from animating during an activity scene animation transition?
Solution 1
There are two approaches you can use that I know of to prevent the navigation/status bar from animating during the transition:
Approach #1: Exclude the status bar and navigation bar from the window's default exit/enter fade transition
The reason why the navigation/status bar are fading in and out during the transition is because by default all non-shared views (including the navigation/status bar backgrounds) will fade out/in in your calling/called Activitys respectively once the transition begins. You can, however, easily get around this by excluding the navigation/status bar backgrounds from the window's default exit/enter Fade
transition. Simply add the following code to your Activitys' onCreate()
methods:
Transition fade = new Fade();
fade.excludeTarget(android.R.id.statusBarBackground, true);
fade.excludeTarget(android.R.id.navigationBarBackground, true);
getWindow().setExitTransition(fade);
getWindow().setEnterTransition(fade);
This transition could also be declared in the activity's theme using XML (i.e. in your own res/transition/window_fade.xml
file):
<?xml version="1.0" encoding="utf-8"?>
<fade xmlns:android="http://schemas.android.com/apk/res/android">
<targets>
<target android:excludeId="@android:id/statusBarBackground"/>
<target android:excludeId="@android:id/navigationBarBackground"/>
</targets>
</fade>
Approach #2: Add the status bar and navigation bar as shared elements
This approach builds off of klmprt's answer, which almost worked for me... although I still needed to make a couple of modifications.
In my calling Activity, I used the following code to start the Activity:
View statusBar = findViewById(android.R.id.statusBarBackground);
View navigationBar = findViewById(android.R.id.navigationBarBackground);
List<Pair<View, String>> pairs = new ArrayList<>();
if (statusBar != null) {
pairs.add(Pair.create(statusBar, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME));
}
if (navigationBar != null) {
pairs.add(Pair.create(navigationBar, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME));
}
pairs.add(Pair.create(mSharedElement, mSharedElement.getTransitionName()));
Bundle options = ActivityOptions.makeSceneTransitionAnimation(activity,
pairs.toArray(new Pair[pairs.size()])).toBundle();
startActivity(new Intent(context, NextActivity.class), options);
So far this is essentially the same thing that klmprt suggested in his answer. However, I also needed to add the following code in my called Activity's onCreate()
method in order to prevent the status bar and navigation bar from "blinking" during the transition:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
// Postpone the transition until the window's decor view has
// finished its layout.
postponeEnterTransition();
final View decor = getWindow().getDecorView();
decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
decor.getViewTreeObserver().removeOnPreDrawListener(this);
startPostponedEnterTransition();
return true;
}
});
}
Adding the status bar and navigation bar backgrounds as shared elements will force them to be drawn on top of the window's default exit/enter fade transition, meaning that they will not fade during the transition. More discussion about this approach can be found in this Google+ post.
Solution 2
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://stackoverflow.com/a/34907685/967131
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.
Solution 3
I just had this same issue, and the answers appear to be missing a critical piece to the puzzle. Remember that on a shared element transition, everything happens in the Destination Activity.
In order to remove the flashing effect, simply add the following to the activity being called:
Fade fade = new Fade();
fade.excludeTarget(android.R.id.statusBarBackground, true);
fade.excludeTarget(android.R.id.navigationBarBackground, true);
getWindow().setEnterTransition(fade);
getWindow().setExitTransition(fade);
This should solve your problem!
Solution 4
As far as I understand this is caused by activity transition overlap. To overcome this issue I have used the following values in the onCreate()
methods of both activities:
getWindow().setAllowEnterTransitionOverlap(false);
getWindow().setAllowReturnTransitionOverlap(false);
Solution 5
You need to share them in ActivityOptions.makeSceneTransitionAnimation.
E.g:
ActivityOptions.makeSceneTransitionAnimation(... Pair.create(activity.findViewById(android.R.id.window_status_bar), Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME)
(excuse the psuedo; I don't have the exact android.R.id value on hand)
You can run an appropriate transition after having shared the views.
![rlay3](https://i.stack.imgur.com/UlsJg.jpg?s=256&g=1)
rlay3
Updated on April 20, 2021Comments
-
rlay3 about 3 years
Firstly, my status bar background is set to dark brown, and my navigation bar background is default black. I'm using the Material light theme.
I'm starting a new activity using
ActivityOptions.makeSceneTransitionAnimation
with default transitions, and I notice that both the status and navigation bars briefly fade to white and then back to the correct colors.According to the documentation:
To get the full effect of a transition, you must enable window content transitions on both the calling and called activities. Otherwise, the calling activity will start the exit transition, but then you'll see a window transition (like scale or fade)
I am using
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
on both the calling and called activities.Similarly, if I change the enter transition to a slide, both the status and navigation bars briefly have a slide transition with a white background.
How do I prevent the status bar and navigation bar from animating during an activity scene animation transition?
-
rlay3 over 9 yearsDid this work for you? I tried this and the status bar and navigation bar still flashes white during the transition.
-
klmprt over 9 yearsYes, it worked for me. Are you sure there isn't another view that might be overlapping them temporarily? Have you tried setting up a simple activity transition in a 'sandboxed' environment to isolate the issue?
-
Alex Lockwood over 9 years@klmprt I think you also need to postpone the enter transition in order to get it working... I also wasn't able to prevent the status/navigation bars from animating simply by sharing the views. I guess you need to wait for the window's decor view to finish its layout before you let the enter transition begin.
-
Alex Lockwood over 9 years@klmprt What my answer still doesn't address though is how to prevent the Action Bar's background color from animating during the transition. If both Activity's share the same Action Bar background color, then the action bar's background color will appear to animate as the calling Activity's action bar gradually fades out and the called Activity's action bar gently fades in. Do you have any idea how to get around this issue?
-
Alex Lockwood over 9 years@klmprt Actually, I think there is an even better solution. You can simply exclude the navigation/status bar backgrounds as targets in the window's default exit/enter fade transition. See my updated answer for details.
-
klmprt over 9 yearsInteresting that you needed the onPreDraw listener -- I thought the framework did that work for you :)
-
Alex Lockwood over 9 years@klmprt It looks like the framework should do that work for you according to the source code... but for some reason it was necessary in order to get the desired effect.
-
Prathamesh Shetye over 9 yearstried this, doesn't work! I wanted the transitions akin to the transitions achieved by using android:transitionName in your layout XMLs... any idea how thats possible???
-
Edward van Raak over 9 yearsWhat would I need to do to prevent the Toolbar from animating in Approach #1?
-
Alex Lockwood over 9 years@EdwardvanRaak I haven't tested this myself, so I could be wrong. But at first glance it looks like the ID is named
R.id.action_bar
in appcompat-v7 (see the source code here: github.com/android/platform_frameworks_support/blob/master/v7/…). I might be wrong though... try it out and let me know if it works. -
radzio over 9 yearsAny ideas why findViewById(android.R.id.navigationBarBackground) is returning null on Lollipop? I am using appcompat-v7
-
Alex Lockwood over 9 years@radzio Are you calling it after you call
setContentView()
on the activity? DoesfindViewById(android.R.id.statusBarBackground)
return null as well? Does it return null for both the called and calling activities during the transition? -
Alex Lockwood over 9 years@radzio Not sure then. But if approach #2 doesn't work for you because it is returning null, you could always try approach #1 as well (which is probably the easier solution anyway).
-
Tony Wickham over 9 yearsAny way to do approach #1 in transition xml?
-
Alex Lockwood over 9 years@TonyWickham I edited my post to include the XML as well. Just set it as the
android:window{Exit,Enter}Transition
in the activity's theme. (BTW, let me know if it works for you work... I didn't test it myself and wrote it off the top of my head. :P I'm pretty sure it will work though). -
Tony Wickham over 9 years@Alex It doesn't stop the action bar from moving, but it does exclude/include other id's so I'm not sure what's wrong...
-
Alex Lockwood over 9 years@TonyWickham If you want to exclude the Action Bar from the transition and you are using AppCompat, try adding
<target android:excludeId="@id/action_bar_container"/>
as well (see this G+ post for some other related details). -
Dima Kornilov over 9 yearsWhat do you think about filing a bug against Android? The framework should always take care of sharing status bar and navigation bar through activity transition. I can't imagine a case when it shouldn't.
-
Dinesh T A over 9 yearsWhat is the TRANSITION_NAME for Action bar? so that i can prevent the action bar from flickering
-
Alex Lockwood over 9 yearsI don't think it has a transition name. But if you are using AppCompat v7 you can reference the action bar's ID instead (R.id.action_bar_container). Or if you are using a Toolbar instead of the action bar, you can give it whatever ID/transition name you want.
-
Akshat about 9 yearsApproach #2 works, but there is still a flicker (in the activity) when the transition happens. the status bar and navigation bar do not flickr anymore.
-
Noa Drach about 9 years@alex This worked almost perfectly for me until we switched to the new support library with android.support.design.widget.TabLayout and android.support.design.widget.AppBarLayout - now the flickering is back
-
goRGon almost 9 yearsI have the same problem with Approach #2. But Approach #1 works for me!
-
Admin almost 9 years@AlexLockwood I'm having the same issue as radzio, findViewById(android.R.id.statusBarBackground) returns null for both Activities. I've tried every combination of solutions, and nothing works exactly how I'd like it to. Adding the toolbar and navigationbar to the transition works perfectly however. It's just that my view is still underneath the statusbar. Is there any other way to get a reference to the statusbar?
-
rekire over 8 yearsI guess I know why
statusBar
is null in my case. I'm using theDrawerLayout
which just paints that area, so there is no view to move... I'll check if I can take theDrawerLayout
itself. Well that causes a funny bug where the hole layout will been pushed down with the statusbar height. -
anandbibek over 8 yearsCan't we do this using fragments in both activities like "ActA+FragA -> ActB+FragB"? If not, how do you suggest we keep this animations on single pane layout, and also have dual pane layout for tablets?
-
Greg Ennis over 8 yearsWhy did google think that it was a good idea that the default behavior cause the status and navigation bar to flash? This is really strange stuff.
-
Etienne Lawlor about 8 yearsThis doesnt seem to work when you have a layout like this gist.github.com/lawloretienne/ef85146dcdbd2a95b96ab796a448c782 I have removed all the attributes so that you can get the gist of what viewgroups are in the layout. This layout being the details screen or second screen you want to transition to.
-
Rafael Sanches about 8 yearsdoes android.R.id.window_status_bar exists for anyone?
-
Etienne Lawlor about 8 yearsI have found a fix for this issue and it is in my repo github.com/lawloretienne/SharedElementTransition
-
Masoud Dadashi about 8 years@toobsco42 what is different in your approach, i saw ur repo and didn't find anything special about it. could you mention the point
-
Boy about 8 yearsandroid.R.id.navigationBarBackground can give you a NPE on Samsung or HTC devices as they don't have an on screen navigation bar. Do a null check before adding them as shared elements
-
Pardeep Kr over 7 yearsI am trying this solution on nexus 6 with android nougat. But both the approaches are not working for me .
-
Pardeep Kr over 7 yearsfindViewById(android.R.id.navigationBarBackground) and findViewById(android.R.id.statusBarBackground) returns null for me .
-
Piotr Zawadzki over 7 yearsApproach #1 didn't work on Nougat for me for some reason, however approach #2 did! Thanks so much!
-
Tim Autin over 6 years@AlexLockwood With an immersive target activity (with a translucent status bar), the status bar still flashes. It works if its opaque, but if translucent, the alpha animation makes it flashes briefly. Do you have a solution? Looks like the status bar background is white whatever is set, while the nav bar works well.
-
rlay3 over 6 yearsHi. Isn't this the same as Approach #1 in the top answer?
-
LukeWaggoner over 6 years@rlay3 Not entirely. As far as I can tell, he never mentions the fact that this need only be set in the destination activity.
-
blackHawk about 6 yearshey @LukeWaggoner could you help me this: stackoverflow.com/questions/50189286/…
-
Sumit Shukla almost 6 yearsHow can i prevent overlapping while performing transitions?? I have tried using: window.setAllowEnterTransitionOverlap(false); and window.setAllowReturnTransitionOverlap(false);
-
shaithana over 4 yearsYou must exclude the statusbar and the navigationbar in both activity, the caller and the called.