改变状态栏颜色

通过Style设置

通过指定主题:android:theme=”@style/AppTheme”

<!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

其中:

  • colorPrimary—导航栏颜色
  • colorPrimaryDark—通知栏颜色
  • colorAccent—控件选中后颜色

代码控制

5.0以上

static void setStatusBarColor(Activity activity, int statusColor) {
    Window window = activity.getWindow();
    //取消状态栏透明
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    //添加Flag把状态栏设为可绘制模式
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    //设置状态栏颜色
    window.setStatusBarColor(statusColor);
    //设置系统状态栏处于可见状态
    window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
    //让view不根据系统窗口来调整自己的布局
    ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
    View mChildView = mContentView.getChildAt(0);
    if (mChildView != null) {
        ViewCompat.setFitsSystemWindows(mChildView, false);
        ViewCompat.requestApplyInsets(mChildView);
    }
}

对于5.0以下的采取组合方式完成

4.4-5.0还没有API可以直接修改状态栏颜色,所以必须先将状态栏设置为透明,然后在布局中添加一个背景为期望色值的View来作为状态栏的填充。

static void setStatusBarColor(Activity activity, int statusColor) {
    Window window = activity.getWindow();
    //设置Window为全透明
    window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

    ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
    //获取父布局
    View mContentChild = mContentView.getChildAt(0);
    //获取状态栏高度
    int statusBarHeight = getStatusBarHeight(activity);

    //如果已经存在假状态栏则移除,防止重复添加
    removeFakeStatusBarViewIfExist(activity);
    //添加一个View来作为状态栏的填充
    addFakeStatusBarView(activity, statusColor, statusBarHeight);
    //设置子控件到状态栏的间距
    addMarginTopToContentChild(mContentChild, statusBarHeight);
    //不预留系统栏位置
    if (mContentChild != null) {
        ViewCompat.setFitsSystemWindows(mContentChild, false);
    }
    //如果在Activity中使用了ActionBar则需要再将布局与状态栏的高度跳高一个ActionBar的高度,否则内容会被ActionBar遮挡
    int action_bar_id = activity.getResources().getIdentifier("action_bar", "id", activity.getPackageName());
    View view = activity.findViewById(action_bar_id);
    if (view != null) {
       TypedValue typedValue = new TypedValue();
        if (activity.getTheme().resolveAttribute(R.attr.actionBarSize, typedValue, true)) {
            int actionBarHeight = TypedValue.complexToDimensionPixelSize(typedValue.data, activity.getResources().getDisplayMetrics());
            setContentTopPadding(activity, actionBarHeight);
        }
    }
}
private static void removeFakeStatusBarViewIfExist(Activity activity) {
    Window window = activity.getWindow();
    ViewGroup mDecorView = (ViewGroup) window.getDecorView();

    View fakeView = mDecorView.findViewWithTag(TAG_FAKE_STATUS_BAR_VIEW);
    if (fakeView != null) {
        mDecorView.removeView(fakeView);
    }
}
private static View addFakeStatusBarView(Activity activity, int statusBarColor, int statusBarHeight) {
    Window window = activity.getWindow();
    ViewGroup mDecorView = (ViewGroup) window.getDecorView();

    View mStatusBarView = new View(activity);
    FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);
    layoutParams.gravity = Gravity.TOP;
    mStatusBarView.setLayoutParams(layoutParams);
    mStatusBarView.setBackgroundColor(statusBarColor);
    mStatusBarView.setTag(TAG_FAKE_STATUS_BAR_VIEW);

    mDecorView.addView(mStatusBarView);
    return mStatusBarView;
}
private static void addMarginTopToContentChild(View mContentChild, int statusBarHeight) {
    if (mContentChild == null) {
        return;
    }
    if (!TAG_MARGIN_ADDED.equals(mContentChild.getTag())) {
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentChild.getLayoutParams();
        lp.topMargin += statusBarHeight;
        mContentChild.setLayoutParams(lp);
        mContentChild.setTag(TAG_MARGIN_ADDED);
    }
}
static void setContentTopPadding(Activity activity, int padding) {
     ViewGroup mContentView = (ViewGroup) activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT);
     mContentView.setPadding(0, padding, 0, 0);
}

状态栏透明

4.4-5.0的处理:

static void translucentStatusBar(Activity activity) {
    Window window = activity.getWindow();
    //设置Window为透明
    window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

    ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
    View mContentChild = mContentView.getChildAt(0);

    //移除已经存在假状态栏则,并且取消它的Margin间距
    removeFakeStatusBarViewIfExist(activity);
    removeMarginTopOfContentChild(mContentChild, getStatusBarHeight(activity));
    if (mContentChild != null) {
        //fitsSystemWindow 为 false, 不预留系统栏位置.
        ViewCompat.setFitsSystemWindows(mContentChild, false);
    }
}

5.0以上的处理:

static void translucentStatusBar(Activity activity, boolean hideStatusBarBackground) {
    Window window = activity.getWindow();
    //添加Flag把状态栏设为可绘制模式
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    if (hideStatusBarBackground) {
        //如果为全透明模式,取消设置Window半透明的Flag
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        //设置状态栏为透明
        window.setStatusBarColor(Color.TRANSPARENT);
        //设置window的状态栏不可见
        window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
    } else {
        //如果为半透明模式,添加设置Window半透明的Flag
        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        //设置系统状态栏处于可见状态
        window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
    }
    //view不根据系统窗口来调整自己的布局
    ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
    View mChildView = mContentView.getChildAt(0);
    if (mChildView != null) {
        ViewCompat.setFitsSystemWindows(mChildView, false);
        ViewCompat.requestApplyInsets(mChildView);
    }
}

fitSystemWindows属性:

  • 官方描述:
    Boolean internal attribute to adjust view layout based on system windows such as the status bar. If true, adjusts the padding of this view to leave space for the system windows. Will only take effect if this view is in a non-embedded activity.
  • 简单描述:
    这个一个boolean值的内部属性,让view可以根据系统窗口(如status bar)来调整自己的布局,如果值为true,就会调整view的paingding属性来给system windows留出空间….
  • 实际效果:
    当status bar为透明或半透明时(4.4以上),系统会设置view的paddingTop值为一个适合的值(status bar的高度)让view的内容不被上拉到状态栏,当在不占据status bar的情况下(4.4以下)会设置paddingTop值为0(因为没有占据status bar所以不用留出空间)。