Android高效进阶:从数据到AI
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.2 沉浸式交互组件

准确地说,“沉浸式状态栏”应该叫“透明栏”,英文名是“Translucent Bars”,它是Android 4.4开始定义的设计规范。简单来说,就是在打开软件的时候通知栏和软件顶部颜色融为一体,这样可以使软件与系统更加融合。

但现在一提到沉浸式状态栏,第一个浮现在脑海里的词就是“碎片化”(Android平台的诞生为手机智能化的普及立下汗马功劳,但Android因开源、设备繁多、品牌众多、版本割裂和分辨率不统一等导致了Android的碎片化,这些都逐渐成为Android系统发展的障碍,碎片化严重不仅造成Android系统混乱,也导致Android应用的隐性开发成本提高)。碎片化是让Android开发者很头疼的问题,相信没有哪位开发者会不喜欢“write once, run anywhere”的感觉,碎片化让大家不得不耗费精力去校验代码在各个系统版本、各个机型上是否有效。

2.2.1 碎片化导致沉浸式适配困难

众所周知,Android原生系统由于本地化支持以及一些组件服务合规等原因,并没有得到推广使用,反而像MIUI、EMUI等基于Android原生系统进行了二次开发的国产ROM,因加入了对中国用户使用习惯等的支持而得到了广泛应用。因此,各个手机厂商统统通过修改Android原生系统,推出了自己的UI ROM。然而,由于UI的制定标准不同、API不同,这给国内的应用开发者造成了很大的伤害,尤其是沉浸式体验这一块。各家UI的制定标准都超出了同期Android原生系统的API标准,因此开发者在适配沉浸式时,需要一个一个系统、一个一个版本地做兼容性适配,工作量较大,难度也比较大。

2.2.2 Android官方沉浸式状态栏方式

在Android系统中,针对StatusBar(状态栏)的操作,一直都在不断改善,并且表现越来越好。在Android 4.4版本以下,我们可以对StatusBar和NavigationBar进行显示和隐藏操作,但是直到Android 4.4版本,我们才实现了真正意义上的沉浸式状态栏。

从Android 4.4到Android 7.1,关于沉浸式大概可以分成如下3个阶段。

Android 4.4(API 19)~Android 5.0(API 21):这个阶段可以实现沉浸式,但是表现得不是很好,实现方式为:通过FLAG_TRANSLUCENT_STATUS设置状态栏为透明和全屏模式,然后添加一个与StatusBar一样大小的View,并将View的background设置为我们想要的颜色,从而实现了沉浸式。

具体方法如下:

    1.   Window win = activity.getWindow();
    2.   WindowManager.LayoutParams winParams = win.getAttributes();
    3.   final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
    4.   winParams.flags |= bits;
    5.   win.setAttributes(winParams);

Android 5.0(API 21)以上的版本:在Android 5.0中,新加入了一个重要的属性android:statusBarColor(对应的方法为setStatusBarColor),通过这个方法我们就可以轻松地实现沉浸式。也就是说,从Android 5.0开始,系统才真正地支持了沉浸式。

具体方法如下:

    1.   Window window = activity.getWindow();
    2.   window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
    3.             | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
    4.   int vis = window.getDecorView().getSystemUiVisibility();
    5.   vis |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
    6.   vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
    7.   window.getDecorView().setSystemUiVisibility(vis);
    8.   window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_
BACKGROUNDS);
    9.   window.setStatusBarColor("yourColor");

Android 6.0(API 23)以上版本:其实Android 6.0以上版本的实现方式和Android 5.0以上版本的实现方式是一样的,这个阶段可以改变状态栏的绘制模式,可以显示白色或浅黑色的内容和图标。

设置方法同Android 5.0,但是可以设置状态栏文字颜色:

    1.   View decorView = activity.getWindow().getDecorView();
    2.   if(decorView != null){
    3.        int vis = decorView.getSystemUiVisibility();
    4.        if(mode == DARK_MODE){
    5.             vis |= SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
    6.        } else {
    7.             vis &= ~SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
    8.        }
    9.        decorView.setSystemUiVisibility(vis);
    10.  }

2.2.3 主流厂商的沉浸式方式简介

由于普遍国内厂商的UI对Android系统进行了大量定制,因此Android原生API设置系统沉浸式的方法在这些UI上无效。如果需要适配这些UI,则需要对这些系统的UI进行深入分析,找出系统的沉浸式设置方法,然后进行沉浸式适配。

下面是国内主流厂商的沉浸式适配方法,通过这些设置方法,可以对国内主流厂商ROM进行沉浸式状态适配。

1.MIUI适配

MIUI在V9版本或者Android 6.0版本之后,使用的是系统方法。然而在V9之前,使用的是MIUI自定义的方法,需要通过反射方式对状态栏的颜色进行设置:

    1.   Window window = activity.getWindow();
    2.   try {
    3.        int darkModeFlag = Reflector.on("android.view.MiuiWindowManager
$LayoutParams")
    4.                  .field("EXTRA_FLAG_STATUS_BAR_DARK_MODE")
    5.                  .get();
    6.        boolean isDark = mode == DARK_MODE;
    7.        int colorMode = isDark ? darkModeFlag : 0;
    8.        Reflector.on(window).call("setExtraFlags", colorMode, darkModeFlag);
    9.   } catch(Exception e){
    10.       e.printStackTrace();
    11.  }

2.OPPO适配

OPPO在Android 5.0以前使用的是系统方法,而在Android 5.0之后的Color OS中,则是通过以下方法设置状态栏颜色的:

    1.   Window window = activity.getWindow();
    2.     if(window != null){
    3.          try {
    4.              Class buildClass =  Class.forName("com.color.os.ColorBuild");
    5.              if(buildClass == null){
    6.                   return;
    7.              }
    8.              Method method = buildClass.getDeclaredMethod("getColor
OSVERSION");
    9.              if(method == null){
    10.                  return;
    11.             }
    12.             method.setAccessible(true);
    13.             int i =(Integer)method.invoke(null);
    14.             if(i < 6){
    15.                  return;
    16.             }
    17.             Class statusBar = Class.forName("com.color.view.
ColorStatusbarTintUtil");
    18.             Field field = statusBar.getDeclaredField("SYSTEM_UI_FLAG_
OP_STATUS_BAR_TINT");
    19.             field.setAccessible(true);
    20.             int values = field.getInt(null);
    21.             int vi;
    22.             if(mode != DARK_MODE){
    23.                 vi = ~values & window.getDecorView().getSystemUiVisibility();
    24.             } else {
    25.                  vi = values | window.getDecorView().getSystemUiVisibility();
    26.             }
    27.             window.getDecorView().setSystemUiVisibility(vi);
    28.
    29.        } catch(Exception e){
    30.             e.printStackTrace();
    31.        }
    32.   }

3.魅族适配

魅族在Android 6.0以后使用系统方法进行沉浸式文字颜色的设置,但是在Android 6.0之前,则需要通过以下方法进行设置:

    1.   Window window = activity.getWindow();
    2.   if(window != null){
    3.        try {
    4.             WindowManager.LayoutParams e = window.getAttributes();
    5.             Field darkFlag = WindowManager.LayoutParams.class.
getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
    6.             Field meizuFlags = WindowManager.LayoutParams.class.
getDeclaredField("meizuFlags");
    7.             darkFlag.setAccessible(true);
    8.             meizuFlags.setAccessible(true);
    9.             int bit = darkFlag.getInt(null);
    10.            int value = meizuFlags.getInt(e);
    11.            if(mode == DARK_MODE){
    12.                 value |= bit;
    13.            } else {
    14.                 value &= ~bit;
    15.            }
    16.            meizuFlags.setInt(e, value);
    17.            window.setAttributes(e);
    18.       } catch(Exception e){
    19.            e.printStackTrace();
    20.       }
    21.  }