沉浸式:Android KITKAT(4.4)以后(包括4.4)

沉浸式:Android KITKAT(4.4)以后(包括4.4)_第1张图片
activity视图.png
//DecorView获取
Activity.getWindow().getDecorView()
//DecorView获取contentView
Activity.findViewById(android.R.id.content)
//获取activity的 setContentView(int LayoutXml);//即我们xml里面写的xml布局
ViewGroup rootView = (ViewGroup) content.getChildAt(0);

全屏化一般用在启动页:
参考:http://blog.csdn.net/lu_ca/article/details/72778694

requestWindowFeature(Window.FEATURE_NO_TITLE);// 隐藏标题
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏

setContentView(R.layout.activity_main);
注意:setContentView一定要写在设置全屏后边

沉浸式的一般套路

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

  • Android4.4(API 19) - Android 5.0(API 21): 这个阶段可以实现沉浸式,但是表现得还不是很好,实现方式为: 通过FLAG_TRANSLUCENT_STATUS设置状态栏为透明并且为全屏模式,这个时候布局会入侵状态栏,我们可以通过添加一个与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)开始,我们可以改状态栏的绘制模式,
    SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
    可以显示白色或浅黑色的内容和图标(除了魅族手机,魅族自家有做源码更改,6.0以下就能实现)

  • 代码未行,效果先上

沉浸式:Android KITKAT(4.4)以后(包括4.4)_第2张图片
image.png
  • Android4.4(API 19) - Android 5.0(API 21)如何实现

在 [KITKAT][null-link] 之后,Android Window支持了一些新的属性,4.4以上能设置沉浸状态栏,正是因为下面的flag引入了,通过这两个flag可以设置Status Bar或Nav Bar透明。设置这个属性不做其他操作一定会入侵状态栏

WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION

View.SYSTEM_UI_FLAG_LAYOUT_STABLEView.SYSTEM_UI_FLAG_LAYOUT_FULLSCRE这两个flag会被自动添加到system UI visibility中。

正如它们的变量名的意思,使用这两个属性,可以使得状态栏和导航栏变为透明,导航栏指的就是Android下方的三大按键,当然只使用第一个属性也可以达到今天所要完成的效果。下面的示例代码将使状态栏和导航栏变得透明
我们注意到上面的flag名为TRANSLUCENT,而不是TRANSPARENT, 知乎 指出了,TranslucentStatus 在 4.4 和 5.x 上表现不同,4.4 是一层渐变的遮罩层,5.x 以上是一条半透明的遮罩层(5.0以上不建议用这个方法,下面有详解),比如Genymotion模拟器上就是这样,但在一些其他机器比如小米上,就是全透明的,这应该是和系统有关的。
Genymotion模拟器4.4上透明状态栏的效果:

沉浸式:Android KITKAT(4.4)以后(包括4.4)_第3张图片
image.png

小米4.4上透明状态栏的效果:
沉浸式:Android KITKAT(4.4)以后(包括4.4)_第4张图片
image.png

Genymotion模拟器5.x上透明状态栏的效果:
沉浸式:Android KITKAT(4.4)以后(包括4.4)_第5张图片
image.png

  @Override
  protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       initWindow();
  }

 @TargetApi(19)
 private void initWindow(){
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
           getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
           getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);   
    }

直接运行之后,状态栏直接透明了,但是并不是我们想要的效果。当设置Status Bar透明后,由于visibility flag的自动添加,屏幕会变成全屏的。所以这时候ToolBar就直接跑到StatusBar下面了,如图:

沉浸式:Android KITKAT(4.4)以后(包括4.4)_第6张图片
image.png

这个问题也很好解决,在 style theme 添加,或者Activity的layout的属性android:fitsSystemWindows="true",但是发现,StatusBar变灰色了。(那是xml里面主布局的颜色,因为fitsSystemWindows是设置padding的,其实只需要把xml主布局颜色设置了就不会变灰了)

沉浸式:Android KITKAT(4.4)以后(包括4.4)_第7张图片
image.png

小结:
Android4.4上实现沉浸式状态栏的套路是:为window添加FLAG_TRANSLUCENT_STATUS Flag

  • 方法1.往DecorView添加一个和status bar 一样大小的View 站位,然后添加setFitsSystemWindows从而让让标题栏不会与status bar 重叠。(因为DecorView是framlayout即使加View也不行把contenView顶下来,所以contenView增加setFitsSystemWindows属性会自定增加status bar的高度)即上面演示的代码。
  • 方法2.不加VIew,直接手动设置xml里面的主布局padding属性为statusView的高度。(不要设置margin会出现状态栏变成灰色)
  • 方法3.最简单,直接设置setFitsSystemWindows后,设置主布局颜色为标题栏颜色就可以了。但是这样的做法不能解决图片问题沉浸式问题。
  • 若:而图片延伸到状态栏只需要设置FLAG_TRANSLUCENT_STATUS就OK
    ps:
    android:clipChildren:clipChildren表示是否限制子View在其范围内,默认true
    android:clipToPadding:ClipToPadding用来定义ViewGroup是否允许在padding中绘制。默认情况下,cliptopadding被设置为ture, 也就是把padding中的值都进行裁切了,如图片超出边界后被裁剪。默认true
  • 2.2 Android 5.0(API 21)以上实现沉浸式的方式

google 加入了一个比较重要的方法setStatusBarColor (对应属性:android:statusBarColor)
注意:想要这个方法生效,必须还要配合一个Flag一起使用,必须设置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS ,并且不能设置FLAG_TRANSLUCENT_STATUS(Android 4.4才用这个)
ps:如果绘制的时候不清除这个flag或者加进去,View.SYSTEM_UI_FLAG_LAYOUT_STABLE的话,实现statusBar绘制了同时,自己的View也会入侵
这个flag 也是在Android 5.0添加的,它的作用是什么呢?

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

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));

Android 5.0图片延伸到状态栏只需设置windowTranslucentStatus,将 statusBarColor 设置为透明即可:就是相当于没有清除FLAG_TRANSLUCENT_STATUS,所以xml入侵了


tip

在Android 5.0 之后我们除了可以在代码中改变状态栏的颜色,还可以在XML中设置主题色,这种方式我们的App不属于沉浸式,在状态栏的下面



沉浸式:Android KITKAT(4.4)以后(包括4.4)_第8张图片
image.png

注意:FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,表明会Window负责系统bar的background 绘制(得先清除4.4的flag),所以不需要设置fitsSystemWindows或者手动设置一个和statusBar一样的大小的View,但是想实现图片沉浸式,要设置windowTranslucentStatus
2.3 Android 6.0 + 实现状态栏字色和图标浅黑色
使用沉浸式的时候会遇到一个问题,那就是Android 系统状态栏的字色和图标颜色为白色,当我的主题色或者图片接近白色或者为浅色的时候,状态栏上的内容就看不清了。 ,这个问题在Android 6.0的时候得到了解决。Android 6.0 新添加了一个属性SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

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

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);
}

除了在代码中添加以外,还可以直接在主题中使用属性:


好了说到这里:如何统一4.4和5.0的沉浸式呢?

个人认为方法有几个方法:

法一:设置 fitsSystemWindows 属性

这样既能解决标题栏入侵状态栏问题,和输入法弹出问题
在 style theme 添加,或者Activity的layout的属性android:fitsSystemWindows="true"!

属性解释:在沉浸式的情况下,如果某个View 的fitsSystemWindows 设为true,那么该View的padding属性将由系统设置,用户在布局文件中设置的padding会被忽略。系统会为该View设置一个paddingTop,值为statusbar的高度。fitsSystemWindows默认为false

参考:https://www.jianshu.com/p/5cc3bd23be7b
设置前这个属性之前是这样的的:

沉浸式:Android KITKAT(4.4)以后(包括4.4)_第9张图片
image.png

但是设置完之后就变成,顶部变白色(其实那是根布局的颜色)


沉浸式:Android KITKAT(4.4)以后(包括4.4)_第10张图片
image.png

解决方法一:根布局设置为标题所需要的颜色
解决方法二:自己在decoView绘制一个和状态栏大小一样,颜色和标题栏一样的View!具体步骤!
解决:自己添加一个带颜色和状态栏一样高的矩形的View

/**
     * 生成一个和状态栏大小相同的矩形条
     *
     * @param activity 需要设置的activity
     * @param color    状态栏颜色值
     * @return 状态栏矩形条
     */
    private static View createStatusView(Activity activity, int color) {
        // 获得状态栏高度
        int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
        int statusBarHeight = activity.getResources().getDimensionPixelSize(resourceId);

        // 绘制一个和状态栏一样高的矩形
        View statusView = new View(activity);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                statusBarHeight);
        statusView.setLayoutParams(params);
        statusView.setBackgroundColor(color);
        return statusView;
    }

整体代码:

   /**
     * 设置状态栏颜色
     *
     * @param activity 需要设置的activity
     * @param color    状态栏颜色值
     */
    public static void setColor(Activity activity, int color) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            // 设置状态栏透明
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            // 生成一个状态栏大小的矩形
            View statusView = createStatusView(activity, color);
            // 添加 statusView 到布局中
            ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
            decorView.addView(statusView);
            // 设置根布局的参数
            ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
            rootView.setFitsSystemWindows(true);
            rootView.setClipToPadding(true);
        }
    }

在 setContentView() 之后调用 setColor(Activity activity, int color) 方法即可。

法二:设置手动设置标题栏的paddingTop

这可以实现titlebar整体文字不入侵状态栏,ImageView整体浸入入侵状态栏,但是得手动解决输入法问题(5.0以后的不要清除FLAG_TRANSLUCENT_STATUS )

/**
 * 通过设置全屏,设置状态栏透明
 *
 * @param activity
 */
private void fullScreen(Activity activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色
            Window window = activity.getWindow();
            View decorView = window.getDecorView();
            //两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间
            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            decorView.setSystemUiVisibility(option);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(Color.TRANSPARENT);
            //导航栏颜色也可以正常设置
//                window.setNavigationBarColor(Color.TRANSPARENT);
        } else {
            Window window = activity.getWindow();
            WindowManager.LayoutParams attributes = window.getAttributes();
            int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
            int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
            attributes.flags |= flagTranslucentStatus;
//                attributes.flags |= flagTranslucentNavigation;
            window.setAttributes(attributes);
        }
    }
}

 public  void setTitleBarPadding(final Activity activity, final View viewPadding) {
        if (viewPadding != null) {
            Object haveSetOffset = viewPadding.getTag(TAG_KEY_HAVE_SET_OFFSET);
            if (haveSetOffset != null && (Boolean) haveSetOffset) {
                return;
            }
            viewPadding.setPadding(viewPadding.getPaddingLeft(), viewPadding.getPaddingTop() + getStatusBarHeight(activity),
                    viewPadding.getPaddingRight(), viewPadding.getPaddingBottom());
            viewPadding.setTag(TAG_KEY_HAVE_SET_OFFSET, true);
        }
      
    }

在 setContentView() 之后调用 fullScreen() 和setTitleBarPadding()方法即可。

法三:直接在标题栏里面设置一个跟状态栏一样大小的View。

得到的效果与2类似。
解决输入法与沉浸式冲突:https://blog.csdn.net/smileiam/article/details/69055963

推荐库:https://github.com/gyf-dev/ImmersionBar
推荐工具类:https://github.com/laobie/StatusBarUtil

你可能感兴趣的:(沉浸式:Android KITKAT(4.4)以后(包括4.4))