系统状态栏与底部导航栏相关工具类

/**
 * 系统状态栏与底部导航栏相关工具类
 * <p>仅在 SDK >= 4.4 时有效</p>
 * <p>本工具类共分两种模式:着色模式{@link #setDisplayOption} 和 全透明模式{@link #fullTransparentBar}</p>
 */
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public final class SystemBarUtil {
    private static final String TAG_STATUS_BAR = "StatusBar";
    private static final String TAG_NAVIGATION_BAR = "NavigationBar";
    /* 无效的颜色值 */
    private static final int INVALID_VAL = -1;
    /* 默认的状态栏颜色 */
    private static final int DEFAULT_STATUS_COLOR = 0x10000000;
    /* 默认的底部导航栏颜色 */
    private static final int DEFAULT_NAVIGATION_COLOR = Color.TRANSPARENT;

    private SystemBarUtil() {
        throw new UnsupportedOperationException("cannot be instantiated");
    }

    /***********************************************************************************************
     ****  沉浸式系统栏(状态栏与导航栏),着色模式,不可全透明(sdk >= 4.4)
     **********************************************************************************************/
    /**
     * 设置状态栏和底部导航栏的显示方式
     *
     * @param activity        activity
     * @param fitSystemWindow {@code true}: 内容不会显示到状态栏和导航栏上<br>{@code false}: 内容显示到状态栏和导航栏上
     * @param clipToPadding   {@code true}: 裁剪 padding 区域,padding 区域不可使用<br>{@code false}: 不裁剪 padding 区域,padding 区域可使用
     */
    public static void setDisplayOption(@NonNull Activity activity, boolean fitSystemWindow, boolean clipToPadding) {
        // 获取根布局
        ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
        rootView.setClipToPadding(clipToPadding);
        rootView.setFitsSystemWindows(fitSystemWindow);
    }

    /**
     * 设置顶部状态栏
     *
     * @param activity
     * @param color    设置顶部状态栏的颜色
     */
    public static void setupStatusBar(@NonNull Activity activity, @ColorInt int color) {
        int statusHeight = ScreenUtil.getStatusBarHeight();
        int statusColor = DEFAULT_STATUS_COLOR;
        if (color != INVALID_VAL) {
            statusColor = color;
        }
        // 设置状态栏透明
        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
        // 防止重复添加 statusBarView
        removeStatusBarView(decorView);
        // 绘制一个和状态栏一样高的矩形 View
        View statusBarView = createStatusBarView(activity, statusHeight, statusColor);
        // 添加 statusBarView 到整个Window的最顶层布局中,这里的 statusBarView 只是作为状态栏的背景,
        // 它的 visible 不能影响到状态栏的 visible
        decorView.addView(statusBarView);
    }

    /**
     * 绘制一个和状态栏一样高的矩形View
     *
     * @param activity
     * @param statusHeight 绘制的矩形的高度
     * @param statusColor  绘制的矩形的颜色
     * @return 绘制的矩形 View
     */
    private static View createStatusBarView(@NonNull Activity activity, int statusHeight, @ColorInt int statusColor) {
        View statusBarView = new View(activity);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, statusHeight);
        params.gravity = Gravity.TOP;
        statusBarView.setLayoutParams(params);
        statusBarView.setBackgroundColor(statusColor);
        statusBarView.setTag(TAG_STATUS_BAR);
        return statusBarView;
    }

    /**
     * 移除已经存在的 statusBarView
     *
     * @param decorView
     */
    private static void removeStatusBarView(@NonNull ViewGroup decorView) {
        View statusBarView = decorView.findViewWithTag(TAG_STATUS_BAR);
        if (statusBarView != null) {
            decorView.removeView(statusBarView);
        }
    }

    /**
     * 设置状态栏的透明度
     *
     * @param activity
     * @param alpha    透明度(0-1)
     */
    public static void setStatusBarAlpha(@NonNull Activity activity, @FloatRange(from = 0, to = 1) float alpha) {
        ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
        View statusView = decorView.findViewWithTag(TAG_STATUS_BAR);
        if (statusView != null) {
            statusView.setAlpha(alpha);
        }
    }

    /**
     * 设置状态栏的显示和隐藏
     *
     * @param activity
     * @param isShow   {@code true}: 显示<br>{@code false}: 隐藏
     */
    public static void showStatusBar(@NonNull Activity activity, boolean isShow) {
        ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
        View statusView = decorView.findViewWithTag(TAG_STATUS_BAR);
        if (isShow) {
            if (statusView != null) {
                statusView.setVisibility(View.VISIBLE);
            }
            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        } else {
            if (statusView != null) {
                statusView.setVisibility(View.GONE);
            }
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }
    }

    /**
     * 设置底部导航栏
     *
     * @param activity
     * @param color    底部导航栏的颜色
     */
    public static void setupNavBar(@NonNull Activity activity, @ColorInt int color) {
        if (ScreenUtil.hasNavigationBar()) {
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            int navHeight = ScreenUtil.getNavBarHeight();
            int navColor = DEFAULT_NAVIGATION_COLOR;
            if (color != INVALID_VAL) {
                navColor = color;
            }
            ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
            removeNavBarView(decorView);
            View navBarView = createNavBarView(activity, navHeight, navColor);
            decorView.addView(navBarView);
        }
    }

    /**
     * 绘制一个和底部导航栏一样高的矩形 View
     *
     * @param activity
     * @param navHeight 绘制的矩形的高度
     * @param navColor  绘制的矩形的颜色
     * @return 绘制的矩形 View
     */
    private static View createNavBarView(@NonNull Activity activity, int navHeight, @ColorInt int navColor) {
        View navBarView = new View(activity);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, navHeight);
        params.gravity = Gravity.BOTTOM;
        navBarView.setLayoutParams(params);
        navBarView.setBackgroundColor(navColor);
        navBarView.setTag(TAG_NAVIGATION_BAR);
        return navBarView;
    }

    /**
     * 移除已经存在的 navBarView
     *
     * @param decorView
     */
    private static void removeNavBarView(@NonNull ViewGroup decorView) {
        View navBarView = decorView.findViewWithTag(TAG_NAVIGATION_BAR);
        if (navBarView != null) {
            decorView.removeView(navBarView);
        }
    }

    /**
     * 设置底部导航栏的透明度
     *
     * @param activity
     * @param alpha    透明度(0-1)
     */
    public static void setNavBarAlpha(@NonNull Activity activity, @FloatRange(from = 0, to = 1) float alpha) {
        if (ScreenUtil.hasNavigationBar()) {
            ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
            View navBarView = decorView.findViewWithTag(TAG_NAVIGATION_BAR);
            if (navBarView != null) {
                navBarView.setAlpha(alpha);
            }
        }
    }

    /**
     * 设置底部导航栏的显示和隐藏
     *
     * @param activity activity
     * @param isShow   {@code true}: 显示<br>{@code false}: 隐藏
     */
    public static void showNavBar(@NonNull Activity activity, boolean isShow) {
        if (ScreenUtil.hasNavigationBar()) {
            View decorView = activity.getWindow().getDecorView();
            if (isShow) {
                decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            } else {
                decorView.setSystemUiVisibility(View.INVISIBLE);
            }
        }
    }

    /***********************************************************************************************
     ****  沉浸式系统栏(状态栏与导航栏),全透明模式,(sdk >= 5.0)
     **********************************************************************************************/
    /**
     * 设置系统栏全透明
     *
     * @param activity
     * @param statusBar 状态栏是否全透明
     * @param navBar    导航栏是否全透明
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public static void fullTransparentBar(Activity activity, boolean statusBar, boolean navBar) {
        Window window = activity.getWindow();
        window.clearFlags(
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                        | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
        if (statusBar && navBar) {
            window.getDecorView().setSystemUiVisibility(
                    // 全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity 顶端布局部分会被状态遮住
                    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                            // 隐藏导航栏
                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                            // 防止系统栏隐藏时内容区域大小发生变化
                            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(Color.TRANSPARENT);
            window.setNavigationBarColor(Color.TRANSPARENT);
        } else if (statusBar && !navBar) {
            window.getDecorView().setSystemUiVisibility(
                    // 全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity 顶端布局部分会被状态遮住
                    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                            // 防止系统栏隐藏时内容区域大小发生变化
                            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(Color.TRANSPARENT);
        } else if (!statusBar && navBar) {
            window.getDecorView().setSystemUiVisibility(
                    // 全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity 顶端布局部分会被状态遮住
                    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                            // 隐藏导航栏
                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                            // 防止系统栏隐藏时内容区域大小发生变化
                            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setNavigationBarColor(Color.TRANSPARENT);
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容