美文网首页
沉浸式:Android KITKAT(4.4)以后(包括4.4)

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

作者: 我一定会学会 | 来源:发表于2018-08-02 11:53 被阅读157次
    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以下就能实现)

    • 代码未行,效果先上

    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上透明状态栏的效果:

    image.png
    小米4.4上透明状态栏的效果:
    image.png
    Genymotion模拟器5.x上透明状态栏的效果:
    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下面了,如图:

    image.png

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

    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入侵了

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

    tip

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

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">    
        <!-- Customize your theme here. -->    
          <!-- Customize your theme here. -->  
        <item name="colorPrimary">@color/colorPrimary</item>       <!-- toolbar -->      
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>   <!-- 状态栏 -->    
        <item name="colorAccent">@color/colorAccent</item>              <!-- 页面中常用控件默认颜色 -->  
        <item name="android:windowBackground">@color/bg_f6</item><!--window背景-->  
    </style>
    
    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);
    }
    

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

    <style name="MDTheme" parent="Theme.Design.Light.NoActionBar">
                  //为了防止冲突取消4.4的透明
            <item name="android:windowTranslucentStatus">false</item>
              //设置5.0的沉浸式
            <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>
       <!-- <item name="android:windowTranslucentStatus">true</item> -->         <!-- 适用4.4到5.0的系统-->  
        </style>
    

    好了说到这里:如何统一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
    设置前这个属性之前是这样的的:

    image.png

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


    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)

          本文链接:https://www.haomeiwen.com/subject/efmcfftx.html