Android UI之系统栏(System Bars)

Android系统栏包括状态栏(status bar)和导航栏(navigation bar)。

开发者可以对系统进行操作,具体包括:

  1. 弱化系统栏(Dimming the System Bars)
  2. 隐藏状态栏(Hiding the Status Bar)
  3. 隐藏导航栏(Hiding the Navigation Bar)
  4. 使用沉浸式全屏模式(Using Immersive Full-Screen Mode)
  5. 响应系统栏的改变(Responding to UI Visibility Changes)
  6. 状态栏上色
  7. 导航栏上色

弱化系统栏

原文参见

什么是弱化系统栏?简而言之就是弱化系统栏对用户的视觉冲击,可以使用户将更多注意力转移到App提供的内容。

要求:弱化系统栏操作,只有Android 4.0或更高版本的设备支持。

效果

  1. 状态栏消失(仍占位);导航栏图标变为小圆点
  2. 不会改变serContentView()方法中参数布局的大小
  3. 用户操作会使系统栏重新可见

实现

// This example uses decor view, but you can use any visible view.
View decorView = getActivity().getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_LOW_PROFILE;
decorView.setSystemUiVisibility(uiOptions);

取消弱化系统栏:

View decorView = getActivity().getWindow().getDecorView();
// Calling setSystemUiVisibility() with a value of 0 clears
// all flags.
decorView.setSystemUiVisibility(0);

隐藏状态栏

原文参见

什么是隐藏状态栏?简而言之就是使状态栏区域的内容消失(占位隐藏);或让状态栏的整个区域都不可见(完全隐藏)。

分类

  1. 占位隐藏
  2. 完全隐藏

占位隐藏实现

这里介绍的实现方法基于Android 4.1及更高的版本。低版本的隐藏参见原文...

int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;//隐藏状态栏
visibleView.setSystemUiVisibility(uiOptions);

完全隐藏实现

这里介绍的实现方法基于Android 4.1及更高的版本。低版本的隐藏参见原文...

int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN//隐藏状态栏
                |View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;//无论状态栏隐藏与否,让布局在状态栏区域显示
visibleView.setSystemUiVisibility(uiOptions);

隐藏导航栏

原文参见

要求:隐藏导航栏操作在Android4.0版本引进。

分类

  1. 占位隐藏
  2. 完全隐藏

占位隐藏实现

int uiOptions = View. SYSTEM_UI_FLAG_HIDE_NAVIGATION;//隐藏导航栏
visibleView.setSystemUiVisibility(uiOptions);

完全隐藏实现

int uiOptions = View. SYSTEM_UI_FLAG_HIDE_NAVIGATION//隐藏导航栏
                |View. SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;//无论导航栏隐藏与否,让布局在导航栏区域显示
visibleView.setSystemUiVisibility(uiOptions);

使用沉浸式全屏模式

原文参见

响应系统栏的改变

原文参见

状态栏上色

参考1


参考2

对于状态栏:

  1. 隐藏
  2. 显示

对于状态栏的隐藏,上文已经介绍。这里介绍状态栏按照需求进行显示的问题。那么,状态栏的显示有哪些需求呢?我分析如下:

  1. 指定状态栏背景颜色
  2. 指定状态栏元素颜色

对于第二个问题,待以后研究,这里只分析如何指定状态栏背景(色)。

API21及以上

设置状态栏背景色的实现可以调用如下方法:

public abstract class Window {
  /**
  For this to take effect,the window must be drawing the system bar backgrounds with 
  android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS and 
  android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS must not be set
  **/
  public abstract void setStatusColor(int color);
}

注意:

  1. 该方法在Android 5.0(API 21)
  2. 引入通过注释可知,要使方法生效,需要其他的操作配合:
    • window不能设置android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS标签
    • window必须设置WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS标签

API20及以下

低版本的系统是不支持给状态栏着色的,但却可以通过透明状态栏+透明背景颜色来实现相同的效果。

  1. 将系统状态栏设置为透明
    • getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  2. 设置Activity根布局的背景颜色为预期状态栏背景色

注意:当设置了状态栏为透明后,Activity会相当于一个FullScreen的全屏设置,窗口会占满整个屏幕,整体的内容会往上移动一段状态栏高度的距离,这样就会导致状态栏覆盖到我们的内容。这时,我们需要在根布局上设置android:fitsSystemWindows="true",这样系统会帮我们重新调整窗口的位置避免出现覆盖的情况(无非就是给我们的窗口加上一个padding值)

沉浸式状态栏

public static void immersingStatusBar(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //5.0以上
            Window window = activity.getWindow();
            //清除导航栏和状态栏的半透明属性
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            //设置系统的ui
            window.getDecorView().setSystemUiVisibility(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 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            //将窗口的状态栏设置成透明的
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }
}

沉浸式导航栏

  • 调用如下方法

关键代码

public void immersingNvigationBar(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0以上
            Window window = activity.getWindow();
            
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);

            window.getDecorView().setSystemUiVisibility(
                    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);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//4.4版本到5.0以下
            Window window = activity.getWindow();
            //将系统栏设置成透明的
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
        }
    }
  • 设置关键元素的margin(包含顶部元素和底部元素)

是否有导航栏

public boolean checkDeviceHasNavigationBar(Context context) {
        boolean hasNavigationBar = false;
        Resources rs = context.getResources();
        int id = rs.getIdentifier("config_showNavigationBar", "bool", "android");
        if (id > 0) {
            hasNavigationBar = rs.getBoolean(id);
        }
        try {
            Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
            Method m = systemPropertiesClass.getMethod("get", String.class);
            String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
            if ("1".equals(navBarOverride)) {
                hasNavigationBar = false;
            } else if ("0".equals(navBarOverride)) {
                hasNavigationBar = true;
            }
        } catch (Exception e) {
        }
        return hasNavigationBar;
    }

获取导航栏高度

    private int getNavigationBarHeight() {
        Resources resources = getResources();
        int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
        int height = resources.getDimensionPixelSize(resourceId);
        Log.v("dbw", "Navi height:" + height);
        return height;
    }

设置底部元素margin

    //设置底部,也可以通过fitsSystemWindows属性实现,但对该属性暂不熟悉,因此使用下面方法保证底部元素不与导航栏重叠
    if(checkDeviceHasNavigationBar(this)){
        FrameLayout.LayoutParams param = (FrameLayout.LayoutParams) llBottom.getLayoutParams();
        param.bottomMargin = getNavigationBarHeight();
        llBottom.setLayoutParams(param);
    }

设置顶部元素margin

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            FrameLayout.LayoutParams param = (FrameLayout.LayoutParams) llBack.getLayoutParams();
            param.topMargin = getStateBarHeight();
            llBack.setLayoutParams(param);
}

沉浸式系统栏

public void immersingSystemBar(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0以上
            Window window = activity.getWindow();
            //清除导航栏和状态栏的半透明属性
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);

            //设置系统的ui
            window.getDecorView().setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION//布局在导航栏区域有值
                            | 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);
            window.setNavigationBarColor(Color.TRANSPARENT);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//4.4版本到5.0以下
                Window window = activity.getWindow();
                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
        }
}

备注

  1. 青葱西点模块首页采用沉浸式系统栏
  2. 青葱西点商品详情界面采用沉浸式状态栏
  3. 罗曼蒂克首页采用沉浸式状态栏

你可能感兴趣的:(Android UI之系统栏(System Bars))