Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android 沉浸式解析和轮子使用

Android 沉浸式解析和轮子使用

作者头像
有赞coder
发布于 2020-08-25 07:27:17
发布于 2020-08-25 07:27:17
3.4K00
代码可运行
举报
运行总次数:0
代码可运行

前言

我们先一起来回顾一下实现沉浸式状态栏的一般套路。在 Android 上,关于对 StatusBar(状态栏)的操作,一直都在不断改善,并且表现越来越好,在 Android4.4 以下,我们可以对 StatusBar 和 NavigationBar 进行显示和隐藏操作。但是直到 Android4.4,我们才能真正意义上的实现沉浸式状态栏。从 Android4.4 到现在(Android 9),关于沉浸式大概可以分成三个阶段:

  • Android4.4(API 19)- Android 5.0(API 21):这个阶段可以实现沉浸式,但是表现得还不是很好,实现方式为: 通过 FLAGTRANSLUCENTSTATUS 设置状态栏为透明并且为全屏模式,然后通过添加一个与 StatusBar 一样大小的 View,将View 的 background 设置为我们想要的颜色,从而来实现沉浸式。
  • Android 5.0(API 21)以上版本:在Android 5.0 的时候,加入了一个重要的属性和方法 android:statusBarColor (对应方法为 setStatusBarColor),通过这个方法我们就可以轻松实现沉浸式。也就是说,从 Android5.0 开始,系统才真正的支持沉浸式。
  • Android 6.0(API 23)以上版本:其实 Android6.0 以上的实现方式和 Android 5.0+是一样,为什么要将它归为一个单独重要的阶段呢?是因为从 Android 6.0(API 23)开始,我们可以改状态栏的绘制模式,可以显示白色或浅黑色的内容和图标(除了魅族手机,魅族自家有做源码更改,6.0 以下就能实现)。

总结:这三个阶段的 Android 上 API 版本混乱,各种 Flag 林立。再加上各大厂商的定制化可谓是火上浇油,让安卓开发者异常头疼。

一、沉浸式三个阶段使用

我们将从沉浸式支持的三个阶段和支持的功能出发,去了解出现的相关背景,然后去了解怎么实现三个阶段的沉浸式。

1.1 Android4.0-Android5.0设置沉浸体验

在 android4.4 及以上版本中为 setSystemUiVisibility() 方法引入了一个新的 flag:SYSTEMUIFLAGIMMERSIVE,它可以使你的 app 实现真正意义上的全屏体验。当 SYSTEMUIFLAGIMMERSIVE、SYSTEMUIFLAGHIDENAVIGATION 和SYSTEMUIFLAG_FULLSCREEN 三个 flag 一起使用的时候,可以隐藏状态栏与导航栏,同时让你的app可以捕捉到用户的所有触摸屏事件。从 Android4.4 以上版本才是真正的可以设置沉浸式体验,但也仅仅是操作状态栏和导航栏的显示与隐藏

1.1.1 FLAGTRANSLUCENTSTATUS

当沉浸式全屏模式启用的时候,你的 activity 会继续接受各类的触摸事件。用户可以通过在状态栏与导航栏原来区域的边缘向内滑动让系统栏重新显示。这个操作清空了 SYSTEMUIFLAGHIDENAVIGATION SYSTEMUIFLAGFULLSCREEN,如果没有两个标志的话,系统栏重新变得可见。如果设置了两个标签的话,这个操作同时也触发了 View.OnSystemUiVisibilityChangeListener。然而, 如果你想让系统栏在一段时间后自动隐藏的话,你应该使用 SYSTEMUIFLAGIMMERSIVE_STICKY 标签

展示了各种不同的“沉浸式”状态:

在上图中:

  • 非沉浸模式 —— 展示了应用进入沉浸模式之前的状态。也展示了设置 IMMERSIVE 标签后用户滑动展示系统栏的状态。用户滑动后, SYSTEMUIFLAGHIDENAVIGATION SYSTEMUIFLAG_FULLSCREEN 就会被清除,系统栏就会重新显示并保持可见。请注意,最好的方式就是让所有的 UI 控件与系统栏的显示隐藏保持同步,这样可以减少屏幕显示所处的状态,同时提供了更无缝平滑的用户体验。因此所有的UI控件跟随系统栏一同显示。一旦应用进入了沉浸模式,UI 控件也跟随着系统栏一同隐藏。为了确保 UI 的可见性与系统栏保持一致,我们需要一个监听器 View.OnSystemUiVisibilityChangeListener 来监听系统栏的变化。这在下一节中将详细讲解。
  • 提示气泡——第一次进入沉浸模式时,系统将会显示一个提示气泡,提示用户如何再让系统栏显示出来。请注意,如果为了测试你想强制显示提示气泡,你可以先将应用设为沉浸模式,然后按下电源键进入锁屏模式,并在 5 秒中之后打开屏幕。
  • 沉浸模式—— 这张图展示了隐藏了系统栏和其他UI控件的状态。你可以设置 IMMERSIVE 和 IMMERSIVE_STICKY 来进入这个状态。
  • 粘性标签——这就是你设置了 IMMERSIVE_STICKY 标签时的 UI 状态,用户会向内滑动以展示系统栏。半透明的系统栏会临时的进行显示,一段时间后自动隐藏。滑动的操作并不会清空任何标签,也不会触发系统 UI 可见性的监听器,因为暂时显示的导航栏并不被认为是一种可见的状态。

注意,immersive 类的标签只有在与 SYSTEMUIFLAGHIDENAVIGATION、SYSTEMUIFLAG_FULLSCREEN 中一个或两个一起使用的时候才会生效。你可以只使用其中的一个,但是一般情况下你需要同时隐藏状态栏和导航栏以达到沉浸的效果。

1.1.2 两种使用这个属性的方式:

  • 在使用时候,我们通常需要考虑的是状态栏一值显示在顶部而不会隐藏或者被遮挡(其他 app 情况如:读书 app 或者是游戏 app 则需要隐藏顶部状态栏),所以只需要通过代码设置 FLAGTRANSLUCENTSTATU
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  • 通过主题theme设置属性windowTranslucentStatus:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<style name="Theme" parent="Theme.Design.Light.NoActionBar">
        <item name="android:windowTranslucentStatus">true</item>
    </style>

效果如下:

效果如上图,可以看出,沉浸式的效果是出来了,但是也有一个问题,我们的标题栏和状态栏重叠了,相当于整个布局上移了StatusBar 的高度。

为了让标题栏回到原来的位置并且适应标题栏的颜色,我们在标题栏的上方添加一个大小和 StatusBar 大小一样假的状态栏 View,View 的 BackgroundColor 可以自己设置成标题栏一样的颜色也可以是其他颜色,这个 View 起到一个占位的作用。这个时候,标题栏就会下移 StatusBar 的高度,回到正常的位置。

通过设置 paddingTop 重新绘制标题栏高度代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
View statusBarView = mDecorView.findViewById(IMMERSION_STATUS_BAR_VIEW);
        if (statusBarView == null) {
            statusBarView = new View(mActivity);
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    mBarConfig.getStatusBarHeight());
            params.gravity = Gravity.TOP;
            statusBarView.setLayoutParams(params);
            statusBarView.setVisibility(View.VISIBLE);
            statusBarView.setId(IMMERSION_STATUS_BAR_VIEW);
            mDecorView.addView(statusBarView);
        }
        if (mBarParams.statusBarColorEnabled) {
            statusBarView.setBackgroundColor(ColorUtils.blendARGB(mBarParams.statusBarColor,
                    mBarParams.statusBarColorTransform, mBarParams.statusBarAlpha));
        } else {
            statusBarView.setBackgroundColor(ColorUtils.blendARGB(mBarParams.statusBarColor,
                    Color.TRANSPARENT, mBarParams.statusBarAlpha));
        }

添加上述代码后,效果如下:

通过以上就可以实现 Android 4.4 上的沉浸式状态栏。

小结:Android4.4-Android5.0的步骤就是为window添加 FLAGTRANSLUCENTSTATUS 的 Flag,然后添加一个假的状态栏,通过上述方法设置的沉浸式在 Android4.4-Android5.0 之间的效果如贴图,状态栏顶部是有一个黑色阴影渐变,在5.0版本版本以上被修复了。如果是一张图片沉浸到状态栏则不需要设置这个假的状态栏,只需要设置,FLAGTRANSLUCENTSTATUS 就 OK。并且在 Android4.4-Android5.0 是没有提供改变状态颜色的属性,所以只能通过新增加一个假的状态栏方式改变背景颜色。

1.2 Android5.0 以上设置状态栏背景颜色

Android 5.0 是一个里程碑式的版本,从Android 5.0 开始,Google 推出了全新的设计规范 Material Design,并且原生控件就可以实现一些炫酷的 UI 动效。从这个版本开始,google 加入了一个比较重要的方法 setStatusBarColor (对应属性:android:statusBarColor),通过这个方法,可以很轻松地实现沉浸式状态栏。方法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public abstract void setStatusBarColor(@ColorInt int color);

注意看这个方法的注释,想要这个方法生效,必须还要配合一个Flag一起使用,必须设置 FLAGDRAWSSYSTEMBARBACKGROUNDS ,并且不能设置 FLAGTRANSLUCENTSTATUS(Android 4.4 才用这个),所以和 4.4 互斥不能共用。所以Android5.0以上可以设置状态栏和导航栏背景颜色,但还不能改变状态栏和导航栏图标和字色。

1.2.1 FLAGDRAWSSYSTEMBARBACKGROUNDS 属性

解释:设置了 FLAGDRAWSSYSTEMBARBACKGROUNDS,表明会 Window 负责系统bar的 background 绘制,绘制透明背景的系统 bar(状态栏和导航栏),然后用 getStatusBarColor() 和 getNavigationBarColor() 的颜色填充相应的区域。这就是 Android 5.0 以上实现沉浸式导航栏的原理。

实现沉浸式添加如下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    //注意要清除 FLAG_TRANSLUCENT_STATUS flag
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    getWindow().setStatusBarColor(getResources().getColor(android.R.color.holo_red_light));

效果如下:

如果在开发的时候是通过设置主题的方式设置,则需要在values-v21文件夹下添加如下主题,达到兼容目的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制


<style name="Theme" parent="Theme.Design.Light.NoActionBar">

        <item name="android:windowTranslucentStatus">false</item>

        <item name="android:windowDrawsSystemBarBackgrounds">true</item>

        <item name="android:statusBarColor">@android:color/holo_red_light</item>

    </style>
1.2.2 图片延伸到状态栏

在 Android 5.0 使图片延伸到状态栏,只需设置 windowTranslucentStatus,将 statusBarColor 设置为透明即可。主题方式设置如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<style name="ImageTranslucentTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
        <item name="android:windowTranslucentNavigation">true</item>
        <item name="android:windowTranslucentStatus">true</item>
        <!-- 设置statusBarColor 为透明-->
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>

在开发过程中,使用代码设置 windowTranslucentStatus 需要通过版本号的判断兼容 Android5.0 以下和 Android 5.0 以上。

1.3 Android 6.0 +实现状态栏字色和图标浅黑色

使用 Android6.0 以下版本沉浸式的时候会遇到一个问题,那就是 Android 系统状态栏的字色和图标颜色为白色,当状态栏颜色接近浅色的时候,状态栏上的内容就看不清了。Android 6.0 新添加了一个属性来解决这个问题,属性是 SYSTEMUIFLAGLIGHTSTATUS_BAR,可以设置状态栏字色和图标浅黑色。

1.3.1 SYSTEMUIFLAGLIGHTSTATUS_BAR

解释:为 setSystemUiVisibility(int) 方法添加的 Flag,请求 status bar 绘制模式,它可以兼容亮色背景的status bar 。要在设置了 FLAGDRAWSSYSTEMBARBACKGROUNDSflag ,同时清除了 FLAGTRANSLUCENTSTATUSflag 才会生效。

通过代码设置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            getWindow().getDecorView().setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}

效果如下:

并且还可以在主题中使用属性,并且该主题需要放在 values-v23 文件夹下相应 Android6.0 以上才能生效:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<style name="Theme" parent="Theme.Design.Light.NoActionBar">
        <item name="android:windowTranslucentStatus">false</item>
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="android:statusBarColor">@android:color/holo_red_light</item>
        <!-- Android 6.0以上 状态栏字色和图标为浅黑色-->
        <item name="android:windowLightStatusBar">true</item>
    </style>

二、ZanImmersionBar 轮子的原理和使用

在实际开发过程中,我们不仅仅只会遇到以上三种版本兼容问题,还需要考虑如:不同手机品牌,动态该状态栏背景,以及 Fragment 中需要有自己的状态栏颜色场景。所以需要综合考虑多种场景,达到能适配多种开发情况的要求。

总结出以下场景:

综合以上场景并且参考github例子进行封装之后得到了 ZanImmersionBar 这个轮子

2.1 原理:

我们希望将设置沉浸式效果都封装在一个类里面,想达到所有的效果通过一个方法设置,但很多的效果中都会有重复的设置步骤,并且每个效果的方法太多则分不清使用哪个,所以将设置沉浸式效果拆分成几个步骤,而想要设置个性效果,通过方法设置参数,最后通过init方法收集所有参数让后统一设置参数属性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZanImmersionBar.with(this).init();//该方法将进行以下步骤处理沉浸式
public void init() {
        //更新Bar的参数
        updateBarParams();
        //设置沉浸式
        setBar();
        //适配状态栏与布局重叠问题
        fitsLayoutOverlap();
        //适配软键盘与底部输入框冲突问题
        fitsKeyboard();
        //变色view
        transformView();
    }

沉浸式设置流程如下图:

这几个步骤其中,获取参数和设置沉浸式是必须经过,下面三种设置是在开发中可能遇到的情况,也是设置参数,如果匹配到了则会进行三种设置的处理,接下来主要分析下第一个步骤和第二步骤。

2.1.1 收集 bar 参数

我们使用一个对象用于存储用户设置的 bar 参数,这些参数有状态栏和导航栏颜色、透明度、显示隐藏等等,通过该对象中的参数来分别设置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class BarParams implements Cloneable {
    /**
     * 状态栏颜色
     */
    @ColorInt
    int statusBarColor = Color.TRANSPARENT;
    /**
     * 导航栏颜色
     */
    @ColorInt
    int navigationBarColor = Color.BLACK;
    /**
     * The Default navigation bar color.
     */
    int defaultNavigationBarColor = Color.BLACK;
    /**
     * 状态栏透明度
     */
    @FloatRange(from = 0f, to = 1f)
    float statusBarAlpha = 0.0f;
    /**
     * 导航栏透明度
     */
    @FloatRange(from = 0f, to = 1f)
    float navigationBarAlpha = 0.0f;
      //等其他属性
    ...
}

而这些属性可以通过以下ZanImmersionBar提供的方法进行个性化设置,而这些方法只是将需要设置的参数添加到BarParams对象中,最后必须调用init将参数设置上去。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZanImmersionBar.with(this)
             .transparentStatusBar()  //透明状态栏,不写默认透明色
             .transparentNavigationBar()  //透明导航栏,不写默认黑色(设置此方法,fullScreen()方法自动为true)
             .transparentBar()             //透明状态栏和导航栏,不写默认状态栏为透明色,导航栏为黑色(设置此方法,fullScreen()方法自动为true)
             .statusBarColor(R.color.colorPrimary)     //状态栏颜色,不写默认透明色
             .navigationBarColor(R.color.colorPrimary) //导航栏颜色,不写默认黑色
             .barColor(R.color.colorPrimary)  //同时自定义状态栏和导航栏颜色,不写默认状态栏为透明色,导航栏为黑色
             .statusBarAlpha(0.3f)  //状态栏透明度,不写默认0.0f
             .navigationBarAlpha(0.4f)  //导航栏透明度,不写默认0.0F
             .barAlpha(0.3f)  //状态栏和导航栏透明度,不写默认0.0f
             .statusBarDarkFont(true)   //状态栏字体是深色,不写默认为亮色
             .navigationBarDarkIcon(true) //导航栏图标是深色,不写默认为亮色
                           //等一些其他方法
             .init();  //必须调用方可沉浸式

设置完参数后,则需要收集这些参数,如果在Fragment中使用,则需要Activity同步Fragment的BarParams参数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//获得Bar相关信息
//如果在Fragment中使用,让Activity同步Fragment的BarParams参数
if (mIsFragment) {
    ZanImmersionBar immersionBar = mImmersionBarMap.get(mActivity.toString());
    if (immersionBar != null) {
        immersionBar.mBarParams = mBarParams;
    }
}

mImmersionBarMap 是个 Map,用于存储每个 Activity 对应的 ZanImmersionBar 对象

  • 原理:其实我们通过沉浸式三代发展史,我们可以知道设置沉浸式都是通过改变Activity的window属性达到沉浸式,所以我们想要在Fragment的定制化沉浸式,其实是通过改变Activity的BarParams参数再设置Activity的沉浸式,所以需要注意对Fragment设置沉浸式前必须保证加载Fragment的Activity先进行了ZanImmersionBar的init初始化。
  • 另例:需要注意dialogFragment和Dialog是有自己的window,该window是属于所属Activity的子window,所以设置dialogFragment和Dialog的沉浸式改变的是自己window里的属性,而不是改变Actvity的window里的属性。
  • 关闭销毁:在activity的onDestroy方法中执行,因为mImmersionBarMap存储了每个Activity对应的ZanImmersionBar对象,所以当Activity关闭了需要及时释放,不然mImmersionBarMap会存在过多无用的ZanImmersionBar对象。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZanImmersionBar.with(this).destroy(); //必须调用该方法,防止内存泄漏
   public void destroy() {
          //取消监听
          cancelListener();
          //删除当前界面对应的ImmersionBar对象
          Iterator<Map.Entry<String, ZanImmersionBar>> iterator = mImmersionBarMap.entrySet().iterator();
          while (iterator.hasNext()) {
              Map.Entry<String, ZanImmersionBar> entry = iterator.next();
              if (entry.getKey().contains(mImmersionBarName) || (entry.getKey().equals(mImmersionBarName))) {
                  iterator.remove();
              }
          }
      }
2.1.2 初始化状态栏和导航栏

该方法则是将上一步的参数进行初始化,初始化过程则会根据沉浸式三个阶段和不同厂商进行区分设置。需要注意小米手机系统有自己定制化设置的属性,所以需要分区设置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void setBar() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !OSUtils.isEMUI3_x()) {
            //适配刘海屏
            fitsNotchScreen();
            //初始化5.0以上,包含5.0
            uiFlags = initBarAboveLOLLIPOP(uiFlags);
            //android 6.0以上设置状态栏字体为暗色
            uiFlags = setStatusBarDarkFont(uiFlags);
            //android 8.0以上设置导航栏图标为暗色
            uiFlags = setNavigationIconDark(uiFlags);
        } else {
            //初始化5.0以下,4.4以上沉浸式
            initBarBelowLOLLIPOP();
        }
             ... 
    }
    if (OSUtils.isMIUI6Later()) {
        //修改miui状态栏字体颜色
        setMIUIBarDark(mWindow, MIUI_STATUS_BAR_DARK, mBarParams.statusBarDarkFont);
        //修改miui导航栏图标为黑色
        if (mBarParams.navigationBarEnable) {
            setMIUIBarDark(mWindow, MIUI_NAVIGATION_BAR_DARK, mBarParams.navigationBarDarkIcon);
        }
    }
    ...
}

我们可以重点看下5.0以上状态栏和导航栏初始化,设置初始化window属性让后设置导航栏和状态栏颜色。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private int initBarAboveLOLLIPOP(int uiFlags) {
    //Activity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态栏遮住。
    uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
    mWindow.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    //判断是否存在导航栏
    if (mBarConfig.hasNavigationBar()) {
        mWindow.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
    }
    //需要设置这个才能设置状态栏和导航栏颜色
    mWindow.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    //设置状态栏颜色
    if (mBarParams.statusBarColorEnabled) {
        mWindow.setStatusBarColor(ColorUtils.blendARGB(mBarParams.statusBarColor,
                mBarParams.statusBarColorTransform, mBarParams.statusBarAlpha));
    } else {
        mWindow.setStatusBarColor(ColorUtils.blendARGB(mBarParams.statusBarColor,
                Color.TRANSPARENT, mBarParams.statusBarAlpha));
    }
      ...
    return uiFlags;
}

通过代码分析可以看到其实 ZanImmersionBar 所做的事情就是将设置沉浸式方法进行步骤拆分和增加个性属性设置,并且将沉浸式三个阶段和不同厂商进行区分独立方法设置调用。

2.2 建议和使用

  • 建议在 BaseActivity 中初始化和销毁
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class BaseActivity extends AppCompatActivity {

         @Override
         protected void onCreate(@Nullable Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             // 所有子类都将继承这些相同的属性,请在设置界面之后设置
             ZanImmersionBar.with(this).init();  
         }
         @Override
         protected void onDestroy() {
             super.onDestroy();
             // 必须调用该方法,防止内存泄漏
             ZanImmersionBar.with(this).destroy();  
         }
     }
  • 展示 Activity 中使用效果

2.3 在 Fragment 使用 ZanImmersionBar

注意在 Fragment 中使用 ZanImmersionBar 需要在承载的 Activity 中初始化 ZanImmersionBar,不然会抛出异常。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public abstract class BaseFragment{
         @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
             super.onViewCreated(view, savedInstanceState);
             initImmersionBar();
    }
         @Override
       public void initImmersionBar() {
            ZanImmersionBar.with(this).keyboardEnable(true).init();
        }
    }

具体的Fragment调用以下方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
    public void initImmersionBar() {
        super.initImmersionBar();
        ZanImmersionBar.with(this)
                .statusBarDarkFont(true)
                .statusBarColor(R.color.btn1)
                .navigationBarColor(R.color.btn1)
                .init();
    }
  • 设置 Fragment 的状态栏颜色和状态栏字体颜色效果

2.4 在 Dialog 中实现沉浸式

在 Dialog 中设置 ZanImmersionBar 方式和在 Fragment 或者 Activity 一样,如果在 Fragment 或者 Activity 中有设置并且 dialog 出现不需要改变状态栏则不用设置 ZanImmersionBar,如果需要做定制化上面的高级用法在 Dialog 也支持

  • 结合 dialogFragment 中使用
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZanImmersionBar.with(this).init();
  • 其他dialog
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZanImmersionBar.with(this, dialog).init();

2.5 在 PopupWindow 中实现沉浸式

重点是调用以下方法,但是此方法会导致有导航栏的手机底部布局会被导航栏覆盖,还有底部输入框无法根据软键盘弹出而弹出。这个属性在顶部弹出的时候是需要使用,如果是底部弹框需要看情况而定。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
popupWindow.setClippingEnabled(false);

2.6 状态栏与布局顶部重叠解决方案,六种方案任选其一(可选)

正常使用 ZanImmersionBar 一般不需要考虑重叠问题但在项目中接入 ZanImmersionBar 并且页面没有考虑给头部控件预留出状态栏的高度,并且需要将页面内容沉浸到状态栏或者做定制化状态栏,这种情况下需要考虑重叠问题。之前说到 Android4.4 版本的时候解决重叠的方式是一种,也可以参考一下几种方式解决状态栏与布局顶部重叠问题。

① 使用 dimen 自定义状态栏高度,不建议使用,因为设备状态栏高度并不是固定的

在 values-v19/dimens.xml 文件下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dimen name="status_bar_height">25dp</dimen>

在values/dimens.xml文件下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dimen name="status_bar_height">0dp</dimen>

然后在布局界面添加view标签,高度指定为statusbarheight

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:app="http://schemas.android.com/apk/res-auto"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:background="@color/darker_gray"
           android:orientation="vertical">

           <View
               android:layout_width="match_parent"
               android:layout_height="@dimen/status_bar_height"
               android:background="@color/colorPrimary" />

           <android.support.v7.widget.Toolbar
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:background="@color/colorPrimary"
               app:title="方法一"
               app:titleTextColor="@android:color/white" />
       </LinearLayout>

② 使用系统的fitsSystemWindows属性,使用该属性不会导致输入框与软键盘冲突问题,不要再Fragment使用该属性

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:orientation="vertical"
           android:fitsSystemWindows="true">
       </LinearLayout>

然后使用ImmersionBar时候必须指定状态栏颜色

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZanImmersionBar.with(this)
            .statusBarColor(R.color.colorPrimary)
            .init();

注意:ZanImmersionBar一定要在设置完布局以后使用

③ 使用ZanImmersionBar的fitsSystemWindows(boolean fits)方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZanImmersionBar.with(this)
            .fitsSystemWindows(true)  //使用该属性,必须指定状态栏颜色
            .statusBarColor(R.color.colorPrimary)
            .init();

④ 使用ZanImmersionBar的statusBarView(View view)方法

在标题栏的上方增加View标签,高度指定为0dp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               xmlns:app="http://schemas.android.com/apk/res-auto"
               android:layout_width="match_parent"
               android:layout_height="match_parent"
               android:background="@color/darker_gray"
               android:orientation="vertical">

               <View
                   android:layout_width="match_parent"
                   android:layout_height="0dp"
                   android:background="@color/colorPrimary" />

               <android.support.v7.widget.Toolbar
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:background="@color/colorPrimary"
                   app:title="方法四"
                   app:titleTextColor="@android:color/white" />
        </LinearLayout>

然后使用ZanImmersionBar的statusBarView方法,指定view就可以啦

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZanImmersionBar.with(this)
               .statusBarView(view)
               .init();
         //或者
         //ZanImmersionBar.setStatusBarView(this,view);

⑤ 使用ZanImmersionBar的titleBar(View view)方法,原理是设置paddingTop

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZanImmersionBar.with(this)
                   .titleBar(view) //可以为任意view,如果是自定义xml实现标题栏的话,最外层节点不能为RelativeLayout
                   .init();
             //或者
             //ZanImmersionBar.setTitleBar(this, view);

⑥ 使用ZanImmersionBar的titleBarMarginTop(View view)方法,原理是设置marginTop

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZanImmersionBar.with(this)
                   .titleBarMarginTop(view)  //可以为任意view
                   .statusBarColor(R.color.colorPrimary)  //指定状态栏颜色,根据情况是否设置
                   .init();
             //或者使用静态方法设置
             //ZanImmersionBar.setTitleBarMarginTop(this,view);

总结

在处理 Android 沉浸式状态栏和导航栏开始会很头大,并且会不理解相关设置的 window 的 FLAG 属性,想要分清楚这些属性的大意需要从出现背景出发拆封,先熟悉沉浸式出现的3个阶段的属性和版本能做什么和不能做什么,然后再去了解各个厂家定制化的属性在哪些版本阶段使用,以及是否需要对异形屏适配,最后才是在实际开发和需求中对状态栏和导航栏处理。不过在 Android6.0 以后版本厂家的定制化状态已经越来越没有意义了,以后 Android 原生趋势也将会让开发者使用沉浸式越来越舒服。

-The End-

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 有赞coder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android开发笔记(一百六十三)高仿京东的沉浸式状态栏
前面的文章介绍了如何实现广告轮播的Banner效果,本想可以告一段落。然而某天产品经理心血来潮,拿着苹果手机,要求像iOS那样把广告图顶到状态栏这儿。刚接到这需求,不禁倒吸一口冷气,又要安卓开发去实现iOS的效果,真是强人所难。翻了翻资料,发现修改状态栏的颜色倒是可行,但要把轮播图顶上去就不容易了。再瞅瞅淘宝和当当,原来两个大厂的App都没做出这个效果。正想跟产品经理说这个实现不了,谁料产品大姐笑盈盈地走过来,指着手机说道:“你看,做成京东这样就行了。”盯着手机看了半晌,京东这厮还真的让轮播图插进状态栏了,于是瞬间石化。下面是京东App的首页头部截图:
aqi00
2019/01/18
1.5K0
Android 沉浸式状态栏的实现
之所以不添加values-v21是因为 Android5.0(api21)的黑色层通过style去掉后 应用切出去后再切进来后会再次出现
码客说
2019/10/22
7450
FlutterComponent最佳实践之沉浸式
首先,我们来修改状态栏的颜色,Flutter提供了SystemChrome.setSystemUIOverlayStyle来修改状态栏和底部导航栏的样式修改,借助它,我们可以很方便的干掉状态栏的默认颜色。
用户1907613
2022/04/01
1.7K1
FlutterComponent最佳实践之沉浸式
Android--沉浸式导航栏适配
本文是用于设配SDK4.4到5.0的沉浸式导航栏适配(4.4下面的实现不了沉浸式),上次说到适配沉浸式状态栏时,为DecorView添加一个View可以是实现,导航栏也同样,但是不是所有手机都有导航栏,所以我们先要判断手机有没有导航栏 public static boolean hasNavigationBar(Context context) { WindowManager windowManager = (WindowManager) context.getSystemServi
aruba
2020/07/03
1.7K0
Android--沉浸式导航栏适配
Android 透明状态栏(伪沉浸式)
而由于 Android API 的不同,需要考虑 4.4、5.0、6.0 前后的不同。
三流之路
2018/09/11
2.5K0
Android 透明状态栏(伪沉浸式)
Android 沉浸式状态栏 以及 伪沉浸式状态栏
和尚我最近在调整页面状态栏的效果,主要包括沉浸式状态栏和伪沉浸状态栏(同事唠嗑给定义的玩的)。 前段时间整理过一篇 Android 沉浸式状态栏的多种样式,现在和尚我在稍微的补充一下,都是在日常应用中测试整理的。
阿策小和尚
2019/08/12
1.7K0
Android 沉浸式状态栏 以及 伪沉浸式状态栏
全屏、沉浸式、fitSystemWindow使用及原理分析:全方位控制“沉浸式”的实现
状态栏与导航栏属于SystemUi的管理范畴,虽然界面的UI会受到SystemUi的影响,但是,APP并没有直接绘制SystemUI的权限与必要。APP端之所以能够更改状态栏的颜色、导航栏的颜色,其实还是操作自己的View更改UI。可以这么理解:状态栏与导航栏拥有自己独立的窗口,而且这两个窗口的优先级较高,会悬浮在所有窗口之上,可以把系统自身的状态栏与导航栏看做全透明的,之所有会有背景颜色,是因为下层显示界面在被覆盖的区域添加了颜色,之后,通过SurfaceFlinger的图层混合,好像是状态栏、导航栏自身有了背景色。看一下一个普通的Activity展示的时候,所对应的Surface(或者说Window也可以)。
看书的小蜗牛
2018/06/29
6K0
全屏、沉浸式、fitSystemWindow使用及原理分析:全方位控制“沉浸式”的实现
Android 沉浸式状态栏的多种样式
和尚我最近正在处理客户端顶部沉浸式展示图片,借此整理了一下和尚自己研究测试的沉浸式状态栏。 沉浸式状态栏大家都很熟悉,即 APP 界面图片延伸到状态栏, 应用本身沉浸于状态栏,即顶部不会默认展示系统的黑条。和尚我技术有限,理解不透彻,仅分享一下自己应用测试中可以呈现的几种样式。
阿策小和尚
2019/08/12
1.5K0
Android 沉浸式状态栏的多种样式
Android--SDK4.4-5.0的沉浸式状态栏适配
1 .FitsSystemWindows和ClipToPadding联合运用 我们找到DecroView中的id为content的Framelayout,添加一个高度为statusBar高度的控件,然后调用下面方法 /** * 设置根布局参数 */ private static void setRootView(Activity activity) { ViewGroup parent = (ViewGroup) activity.findViewById
aruba
2020/07/02
6990
关于 Android 状态栏的适配总结
Android 5.0 及其以后版本:设置属性 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 使得我们的内容布局可以延伸到系统状态栏,然后直接使用方法 setStatusBarColor() 把系统状态栏设置成透明就好了。
开发者
2019/12/26
1.2K0
关于 Android 状态栏的适配总结
教你自己写Android第三方库
其实Android studio的出现很大程度上方便了我们Android开发人员,今天我们说说怎么构建我们自己的库。 依次按File->New Moudle->android Library就好了,这
xiangzhihong
2018/02/05
1.8K0
教你自己写Android第三方库
沉浸式状态栏的三种实现方式
沉浸式算是目前Android行业比较流行的一种App设计风格,将菜单栏北京设置为导航栏的颜色,感觉顶部状态栏像是被入侵了一样,因此称为沉浸式菜单栏。本文将介绍三种方式去实现沉浸式状态栏。
开发者技术前线
2020/11/23
1.8K0
沉浸式状态栏的三种实现方式
Android如何实现超级棒的沉浸式体验
做APP开发的过程中,有很多时候,我们需要实现沉浸式的体验。
老码小张
2018/10/25
3K1
沉浸式状态栏的封装使用
  随着用户要求的不断提高,Android版本的不断升级,沉浸式状态栏似乎已经成为了每个App的必备功能。   首先要实现它我们得先理解他,状态栏不同于标题栏,状态栏是Android手机自带的,显示一些Android内置的信息。正常情况下位于我们标题栏上方,以黑色居多。我们的标题栏多数是不会使用黑色标题的,所以,如果不控制状态栏的颜色,就是和我们的标题栏有明显的色彩差。   在笔者的使用中,沉浸式状态栏分为两种:
饮水思源为名
2018/09/06
1.1K0
沉浸式状态栏的封装使用
Android 沉浸式适配 4.4+
Android 沉浸式适配 4.4+ 默认的主题 (/values/styles.xml) <style name="BaseTheme" parent="Theme.AppCompat.Light.NoActionBar"></style> 兼容Android 4.4 (/values-v19/styles.xml) <style name="BaseTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:wind
Xiaolei123
2019/04/17
6610
Android 5.0以上系统常用控件着色指南
当我们新建一个项目的时候,都会给Application或者某些Activity设置theme:
蜻蜓队长
2018/08/03
9750
Android 5.0以上系统常用控件着色指南
Android状态栏颜色修改
Android 4.4(API 19)之后,就提供了修改状态栏颜色的方法,但是在 Android 6.0(API 23)之后,才支持修改状态栏上面的文字和图标颜色,默认是白色的。所以会导致一个问题,在 4.4 到 6.0 之间的系统,状态栏设置为浅色的话,状态栏上面白色的文字和图标会看不清
码客说
2020/11/09
4.2K0
Android状态栏颜色修改
沉浸式管理:让你的APP更优雅
http://www.jianshu.com/u/e01fe6ddfa1c
陈宇明
2020/12/15
1.9K0
沉浸式管理:让你的APP更优雅
相关推荐
Android开发笔记(一百六十三)高仿京东的沉浸式状态栏
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验