When using ActionMode, the status bar turns black on Lollipop

折月煮酒 提交于 2019-11-30 08:02:23

I'm posting an answer here because, while the other solutions were helpful, none of them answered the question exactly. I was able to find out that the call to DrawerLayout.setStatusBarBackgroundColor() was causing the trouble. My solution is the following:

  1. Enable windowTranslucentStatus and windowDrawsSystemBarBackgrounds in the main theme.
  2. Remove the call to DrawerLayout.setStatusBarBackgroundColor() inside of my NavigationDrawerActivity, from which all Activity classes derive.
  3. Set the following styles in my values-v21/styles.xml base theme:
        @color/app_green
        @color/app_green
        @color/app_green_dark
        @color/app_green_dark
        ?attr/colorPrimaryDark
        ?attr/colorPrimaryDark
  1. Inside of the NavigationDrawerActivity class, in its onCreate() method, I execute the following (thanks @Tinadm for this part of the answer): getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

  2. Inside of my class that presents the ActionMode, I added the following methods:

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        // This is to highlight the status bar and distinguish it from the action bar,
        // as the action bar while in the action mode is colored app_green_dark
        getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.app_green_darker));
      }

      // Other stuff...
      return true;
    }

    @Override
    public void onDestroyActionMode(ActionMode mode) {
      mActionMode = null;
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.app_green_dark));
      }
    }

Re-enabling the translucent status bar when the ActionMode is destroyed enables my navigation drawer to be drawn underneath the status bar. It's also worth noting that the ActionMode overlays the action bar, so it will overlay the navigation drawer if it's pulled out when the ActionMode is enabled (via swiping left-to-right). I am going to disable this functionality when the ActionMode is enabled, so it doesn't confuse users.

Elltz

well your temporary solution is call this code when you most need it or when the problem starts

if(Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP){
    getWindow().setStatusBarColor(Color.BLUE); 
    // or Color.TRANSPARENT or your preferred color
}

EDIT

have you tried this

// actionMode.getCustomView().setBackgroundColor.(Color.TRANSPARENT);

@Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {    
    //but this time you let the actionmode's view change the statusbar's
    // visibility
    actionMode.getCustomView().setSystemUiVisibility(
        View.SYSTEM_UI_FLAG_LOW_PROFILE); //or preferred one
    return true;
}

when your actionMode is destroyed, the status bar will be restored, so override that too and re-set your statusBar color.

hope it helps

I ran into the same problem a while ago and my resolution was to in onCreateActionMode & onDestroyActionMode set and restore the statusbar color.

//onCreateActionMode
mStartColor =  activity.getWindow().getStatusBarColor();
getWindow().setStatusBarColor(color);

//onDestroyActionMode
activity.getWindow().setStatusBarColor(mStartColor);

Of course youll need to check that its on lolipop before using the setStatusBarColor method as its not available pre L.

Extra: If you use a DrawerLayout youll need to set the statusBarColor on it too.

mDrawerLayout.setStatusBarBackground(new ColorDrawable(color));

Hope that helps!

I was having the exactly same issue as you. I managed to solve it using a workaround.

  1. The first thing I did was to remove windowTranslucentStatus=true from my theme;
  2. Then I used getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); to make the content fill the area under the status bar.
  3. I set <item name="android:colorPrimaryDark">@color/primary_dark</item> where primary_dark is "#51000000". Note the alpha value to achieve the same trasparency that windowTranslucent provides. Since my Toolbar is blue, my status bar is now dark blue.
  4. This alone did not solve the problem. When action mode is active, the status bar was still black in my case. But now, not using translucentStatusBar, I'm able to apply colors to my status bar, so I used:

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        getActivity().getWindow().setStatusBarColor(Color.parseColor("#026592"));
        return true;
    }
    

(Note that the color I used does not have alpha. This is the RGB color the exactly matches my dark blue semi transparent status bar).

Looking through the Android documentation on Translucent system bars

If you're creating a custom theme, set one of these themes ( Theme.Holo.NoActionBar.TranslucentDecor and Theme.Holo.Light.NoActionBar.TranslucentDecor) as the parent theme or include the windowTranslucentNavigation and windowTranslucentStatus style properties in your theme.

So if you are using the Support Libraries, your style must extend some of the AppCompat styles and use both windowTranslucentNavigation and windowTranslucentStatus on your ActionBarStyle.

The problem might be here.

<item name="android:background">@color/myapp_green</item>
<item name="background">@color/myapp_green</item>

"android:background" is a proper syntax, I don't think "background" is. Why do you need to specify the background color twice anyway? Remove the second one and it should be fine. If not, then I hope my 2 cents below on the subject of setBackgroundColor methods help.

$0.02

In my experience, I have found that from time to time setBackgroundColor() method in Android behave strangely. When that happens, I use setBackground() instead, and specify the color in a drawable form: getResources().getDrawable(R.color.xxxx). I never found out why this resolved similar problems I've had in the past, but I've used this workaround so far without any obvious side effects. It might not be the best solution (especially if you're already setting a background drawable), but it comes in handy when nothing else seems to work.

I got the same issue and I resolved it in the following way

The issue was with overriding the same color for all views.But I's not able to go with R.color.mycolor and Color.parseColor("#412848") saved me.

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        super.onPrepareActionMode(mode, menu);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Window w = getActivity().getWindow();
            w.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            w.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }
        return true;
    }

    @Override
    public void onDestroyActionMode(ActionMode mode) {
        super.onDestroyActionMode(mode);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Window w = getActivity().getWindow();
            w.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
                    WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            w.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
                    WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }
    }
Learn OpenGL ES

While I used the previous solutions earlier, there are more issues when adding a navigation drawer, if you want the drawer to draw behind the system bar, and so many glitches related to setting and clearing window flags or the status bar color (even the official Gmail app has these glitches!)

Here's the solution I use now:

@Override
public void onSupportActionModeStarted(@NonNull ActionMode mode) {
    super.onSupportActionModeStarted(mode);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        // Post this so it ideally happens after the window decor callbacks.
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                try {
                    final AppCompatDelegate delegate = getDelegate();
                    final Class clazz = Class.forName("android.support.v7.app.AppCompatDelegateImplV7");
                    final Field mStatusGuardField = clazz.getDeclaredField("mStatusGuard");
                    mStatusGuardField.setAccessible(true);
                    final View mStatusGuard = (View) mStatusGuardField.get(delegate);
                    if (mStatusGuard != null) {
                        mStatusGuard.setBackgroundColor(/* Should match your desired status bar color when the action mode is showing, or alternatively you could use Color.TRANSPARENT here and just update the colors through getWindow().setStatusBarColor() below. The key is to avoid the black status guard from appearing. */);
                    }
                } catch (Exception e) {
                    /* Log or handle as desired. */
                }
            }
        });
        // Also set the status bar color. This is to avoid a momentary frame or 
        // two where the black will still be visible.
       getWindow().setStatusBarColor(/* Should match your desired status bar color when the action mode is showing. */);
    }
}

@Override
public void onSupportActionModeFinished(@NonNull ActionMode mode) {
    super.onSupportActionModeFinished(mode);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        // Reset to the theme's colorPrimaryDark. This would normally result in 
        // the black status guard being seen momentarily, but because we set it 
        // to the same color as the action mode background, this intermediate 
        // state is not visible.
        getWindow().setStatusBarColor(Color.TRANSPARENT);
    }
}

This is obviously a big hack, and it doesn't animate exactly as the contextual action bar does, but it does the trick for me. Props to https://stackoverflow.com/a/38702953/1317564 for coming up with the idea.

Note that this is only needed if you're using a navigation drawer or otherwise have these attributes set in your values-v21/theme.xml:

<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>

Otherwise, it will probably work to just call setStatusBarColor(...) in onSupportActionModeStarted() and onSupportActionModeFinished(), and this is what I was doing before adding a navigation drawer.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!