精华内容
下载资源
问答
  • Android状态栏微技巧,带你真正理解沉浸式模式

    万次阅读 多人点赞 2016-08-23 07:32:55
    记得之前有朋友在留言里让我写一篇关于沉浸式状态栏的文章,正巧我确实有这个打算,那么本篇就给大家带来一次沉浸式状态栏的微技巧讲解。 其实说到沉浸式状态栏这个名字我也是感到很无奈,真不知道这种叫法是谁先...

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/51763825

    本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,每天都有文章更新。

    记得之前有朋友在留言里让我写一篇关于沉浸式状态栏的文章,正巧我确实有这个打算,那么本篇就给大家带来一次沉浸式状态栏的微技巧讲解。

    其实说到沉浸式状态栏这个名字我也是感到很无奈,真不知道这种叫法是谁先发起的。因为Android官方从来没有给出过沉浸式状态栏这样的命名,只有沉浸式模式(Immersive Mode)这种说法。而有些人在没有完全了解清楚沉浸模式到底是什么东西的情况下,就张冠李戴地认为一些系统提供的状态栏操作就是沉浸式的,并且还起了一个沉浸式状态栏的名字。

    比如之前就有一个QQ群友问过我,像饿了么这样的沉浸式状态栏效果该如何实现?

    这个效果其实就是让背景图片可以利用系统状态栏的空间,从而能够让背景图和状态栏融为一体。

    本篇文章当中我会教大家如何实现这样的效果,但这个真的不叫沉浸式状态栏。因此,这算是一篇技术+普及的文章吧,讲技术的同时也纠正一下大家之前错误的叫法。

    什么是沉浸式?

    先来分析一下叫错的原因吧,之所以很多人会叫错,是因为根本就不了解沉浸式是什么意思,然后就人云亦云跟着叫了。那么沉浸式到底是什么意思呢?

    根据百度百科上的定义,沉浸式就是要给用户提供完全沉浸的体验,使用户有一种置身于虚拟世界之中的感觉。

    比如说现在大热的VR就是主打的沉浸式体验。

    那么对应到Android操作系统上面,怎样才算是沉浸式体验呢?这个可能在大多数情况下都是用不到的,不过在玩游戏或者看电影的时候就非常重要了。因为游戏或者影视类的应用都希望能让用户完全沉浸在其中,享受它们提供的娱乐内容,但如果这个时候在屏幕的上方还显示一个系统状态栏的话,可能就会让用户分分钟产生跳戏的感觉。

    那么我们来看一下比较好的游戏都是怎么实现的,比如说海岛奇兵:

    海岛奇兵的这种模式就是典型的沉浸式模式,它的整个屏幕中显示都是游戏的内容,没有状态栏也没有导航栏,用户玩游戏的时候就可以完全沉浸在游戏当中,而不会被一些系统的界面元素所打扰。

    然后我们再来看一下爱奇艺的实现:

    同样也是类似的,爱奇艺将整个屏幕作为影视的展示区,用户在看电影的时候眼中就只会有电影的内容,这样就不会被其他一些无关的东西所分心。

    这才是沉浸式模式的真正含义,而所谓的什么沉浸式状态栏纯粹就是在瞎叫,完全都没搞懂“沉浸式” 这三个字是什么意思。

    不过虽然听上去好像是很高大上的沉浸式效果,实际看上去貌似就是将内容全屏化了而已嘛。没错,Android沉浸式模式的本质就是全屏化,不过我们今天的内容并不仅限于此,因为还要实现饿了么那样的状态栏效果。那么下面我们就开始来一步步学习吧。

    隐藏状态栏

    一个Android应用程序的界面上其实是有很多系统元素的,观察下图:

    可以看到,有状态栏、ActionBar、导航栏等。而打造沉浸式模式的用户体验,就是要将这些系统元素全部隐藏,只留下主体内容部分。

    比如说我现在新建了一个空项目,然后修改布局文件中的代码,在里面加入一个ImageView,如下所示:

    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/bg"
            android:scaleType="centerCrop" />
    
    </RelativeLayout>

    这里将ImageView的宽和高都设置成match_parent,让图片充满屏幕。现在运行一下程序,效果如下图所示。

    如果你将图片理解成游戏或者电影界面的话,那这个体验离沉浸式就差得太远了,至少状态栏和ActionBar得要隐藏起来了吧?没关系,我们一步步进行优化,并且在优化中学习。

    隐藏状态栏和ActionBar的方式在4.1系统之上和4.1系统之下还是不一样的,这里我就不准备考虑4.1系统之下的兼容性了,因为过于老的系统根本就没有提供沉浸式体验的支持。

    修改MainActivity中的代码,如下所示:

    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            View decorView = getWindow().getDecorView();
            int option = View.SYSTEM_UI_FLAG_FULLSCREEN;
            decorView.setSystemUiVisibility(option);
            ActionBar actionBar = getSupportActionBar();
            actionBar.hide();
        }
    }

    这里先调用getWindow().getDecorView()方法获取到了当前界面的DecorView,然后调用它的setSystemUiVisibility()方法来设置系统UI元素的可见性。其中,SYSTEM_UI_FLAG_FULLSCREEN表示全屏的意思,也就是会将状态栏隐藏。另外,根据Android的设计建议,ActionBar是不应该独立于状态栏而单独显示的,因此状态栏如果隐藏了,我们同时也需要调用ActionBar的hide()方法将ActionBar也进行隐藏。

    现在重新运行一下程序,效果如下图所示。

    这样看上去就有点沉浸式效果的模样了。

    虽说这才是正统的沉浸式含义,但有些朋友可能想实现的就是饿了么那样的状态栏效果,而不是直接把整个系统状态栏给隐藏掉,那么又该如何实现呢?

    其实也很简单,只需要借助另外一种UI Flag就可以了,如下所示:

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (Build.VERSION.SDK_INT >= 21) {
        View decorView = getWindow().getDecorView();
        int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
        decorView.setSystemUiVisibility(option);
        getWindow().setStatusBarColor(Color.TRANSPARENT);
    }
    ActionBar actionBar = getSupportActionBar();
    actionBar.hide();

    首先需要注意,饿了么这样的效果是只有5.0及以上系统才支持,因此这里先进行了一层if判断,只有系统版本大于或等于5.0的时候才会执行下面的代码。

    接下来我们使用了SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_STABLE,注意两个Flag必须要结合在一起使用,表示会让应用的主体内容占用系统状态栏的空间,最后再调用Window的setStatusBarColor()方法将状态栏设置成透明色就可以了。

    现在重新运行一下代码,效果如下图所示。

    可以看到,类似于饿了么的状态栏效果就成功实现了。

    再声明一次,这种效果不叫沉浸式状态栏,也完全没有沉浸式状态栏这种说法,我们估且可以把它叫做透明状态栏效果吧。

    隐藏导航栏

    现在我们已经成功实现隐藏状态栏的效果了,不过屏幕下方的导航栏还比较刺眼,接下来我们就学习一下如何将导航栏也进行隐藏。

    其实实现的原理都是一样的,隐藏导航栏也就是使用了不同的UI Flag而已,修改MainActivity中的代码,如下所示:

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    View decorView = getWindow().getDecorView();
    int option = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_FULLSCREEN;
    decorView.setSystemUiVisibility(option);
    ActionBar actionBar = getSupportActionBar();
    actionBar.hide();

    这里我们同时使用了SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN,这样就可以将状态栏和导航栏同时隐藏了。现在重新运行一下程序,效果如图所示。

    这次看上去好像终于是完全全屏化了,但其实上这离真正的沉浸式模式还差得比较远,因为在这种模式下,我们触摸屏幕的任意位置都会退出全屏。

    这显然不是我们想要的效果,因此这种模式的使用场景比较有限。

    除了隐藏导航栏之外,我们同样也可以实现和刚才透明状态栏类似的效果,制作一个透明导航栏:

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (Build.VERSION.SDK_INT >= 21) {
        View decorView = getWindow().getDecorView();
        int option = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
        decorView.setSystemUiVisibility(option);
        getWindow().setNavigationBarColor(Color.TRANSPARENT);
        getWindow().setStatusBarColor(Color.TRANSPARENT);
    }
    ActionBar actionBar = getSupportActionBar();
    actionBar.hide();

    这里使用了SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,表示会让应用的主体内容占用系统导航栏的空间,然后又调用了setNavigationBarColor()方法将导航栏设置成透明色。现在重新运行一下程序,效果如下图所示。

    真正的沉浸式模式

    虽说沉浸式导航栏这个东西是被很多人误叫的一种称呼,但沉浸式模式的确是存在的。那么我们如何才能实现像海岛奇兵以及爱奇艺那样的沉浸式模式呢?

    首先你应该确定自己是否真的需要这个功能,因为除了像游戏或者视频软件这类特殊的应用,大多数的应用程序都是用不到沉浸式模式的。

    当你确定要使用沉浸式模式,那么只需要重写Activity的onWindowFocusChanged()方法,然后加入如下逻辑即可:

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        @Override
        public void onWindowFocusChanged(boolean hasFocus) {
            super.onWindowFocusChanged(hasFocus);
            if (hasFocus && Build.VERSION.SDK_INT >= 19) {
                View decorView = getWindow().getDecorView();
                decorView.setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
            }
        }
    
    }

    沉浸式模式的UI Flag就这些,也没什么好解释的,如果你需要实现沉浸式模式,直接将上面的代码复制过去就行了。需要注意的是,只有在Android 4.4及以上系统才支持沉浸式模式,因此这里也是加入了if判断。

    另外,为了让我们的界面看上去更像是游戏,这里我将MainActivity设置成了横屏模式:

    <activity android:name=".MainActivity" 
              android:screenOrientation="landscape">
        ...
    </activity>

    这样我们就实现类似于海岛奇兵和爱奇艺的沉浸式模式效果了,如下图所示。

    可以看到,界面默认情况下是全屏的,状态栏和导航栏都不会显示。而当我们需要用到状态栏或导航栏时,只需要在屏幕顶部向下拉,或者在屏幕右侧向左拉,状态栏和导航栏就会显示出来,此时界面上任何元素的显示或大小都不会受影响。过一段时间后如果没有任何操作,状态栏和导航栏又会自动隐藏起来,重新回到全屏状态。

    这就是最标准的沉浸式模式。


    关注我的技术公众号,每天都有优质技术文章推送。关注我的娱乐公众号,工作、学习累了的时候放松一下自己。

    微信扫一扫下方二维码即可关注:

    20160507110203928         20161011100137978

    展开全文
  • 实现4.4以后的状态栏与app的导航栏颜色相同,android沉浸式状态栏、变色状态栏、透明状态栏、修改状态栏颜色及透明。
  • 今天总结一下状态栏的使用,当然也是参考别人的。但是总归自己得试试,然后把常用的几种情况记下来,因为这些东西是死的,下次拿过来就可以用。 一. 沉浸式状态栏 :Android 5.0以上才会支持沉浸式状态栏效果。 ...

    今天总结一下状态栏的使用,当然也是参考别人的。但是总归自己得试试,然后把常用的几种情况记下来,因为这些东西是死的,下次拿过来就可以用。

    一. 沉浸式状态栏  :Android 5.0以上才会支持沉浸式状态栏效果。 下面就建立一个默认的项目。1.状态栏(背景色是蓝色,字体图标是白色的)2.ActionBar,一般都不用的 3.内容 4.虚拟键。       所谓沉浸式状态栏就是只有3着哭泣区域占据整个屏幕,如爱奇艺全屏模式,玩王者荣耀的时候。但是一般情况下我们开发的APP都不会用到的,所以那里的沉浸式状态栏就是:去掉ActionBar,内容区占据状态栏(他俩重合),并且状态栏的透明或者半透明状态。行了直接上代码吧。

    1.完全的沉浸式状态栏(下图):

    代码:

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus && Build.VERSION.SDK_INT >= 19) {
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION  
                            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                            | View.SYSTEM_UI_FLAG_FULLSCREEN
                            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
        }
    }

    图1

    2.状态栏透明+底部导航栏透明+主体内容充满整个屏幕+去掉ActionBar(这种可以某些布局会影响操作  使用不多)

    代码:

    if (Build.VERSION.SDK_INT >= 21) {
        View decorView = getWindow().getDecorView();
        int option = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
        decorView.setSystemUiVisibility(option);
        getWindow().setNavigationBarColor(Color.TRANSPARENT);
        getWindow().setStatusBarColor(Color.TRANSPARENT);
    }
    ActionBar actionBar = getSupportActionBar();
    actionBar.hide();  

    图2:

    3.状态栏透明+主体内容上部延伸到状态栏+去掉ActionBar

    代码:

    if (Build.VERSION.SDK_INT >= 21) {
        View decorView = getWindow().getDecorView();
        int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
        decorView.setSystemUiVisibility(option);
        getWindow().setStatusBarColor(Color.TRANSPARENT);
    }
    ActionBar actionBar = getSupportActionBar();
    actionBar.hide();

    图3.

    注意: 1.使用沉浸式状态栏一定不要在Activity中的xml根布局中使用:

    android:fitsSystemWindows="true"

    2.如果不想在代码里面去掉ActionBar可以直接在style中修改Theme为:

    parent="Theme.AppCompat.Light.NoActionBar"

    二.如何修改状态栏的背景颜色和字体,图表颜色

    1.状态栏字体颜色,我只接上工具类代码以及相关代码:

    StateUtils:直接使用的工具类

    SystemBarTintManager:修改状态颜色的辅助类
    RomUtils:设置状态栏字体时候 怼不通机型进行适配

    使用:

    //设置状态蓝的颜色,也可以给颜色本身设置透明度,自己试试
    StateUtils.setStatusBarColor(this, R.color.colorAccents);
    //设置状态栏字体颜色,true:代表黑色,false代表白色
    StateUtils.setLightStatusBar(this, true);
    public class StateUtils {
    
        /**
         * 1.修改状态栏颜色,支持4.4以上版本
         * @param activity
         * @param colorId
         */
        public static void setStatusBarColor(Activity activity, int colorId) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Window window = activity.getWindow();
                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                window.setStatusBarColor(activity.getResources().getColor(colorId));
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                //使用SystemBarTint库使4.4版本状态栏变色,需要先将状态栏设置为透明
                transparencyBar(activity);
                SystemBarTintManager tintManager = new SystemBarTintManager(activity);
                tintManager.setStatusBarTintEnabled(true);
                tintManager.setStatusBarTintResource(colorId);
            }
        }
    
    
    
        /**
         *  2.修改状态栏文字颜色,这里小米,魅族区别对待。
         */
        public static void setLightStatusBar(final Activity activity, final boolean dark) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                switch (RomUtils.getLightStatusBarAvailableRomType()) {
                    case RomUtils.AvailableRomType.MIUI:
                        MIUISetStatusBarLightMode(activity, dark);
                        break;
    
                    case RomUtils.AvailableRomType.FLYME:
                        setFlymeLightStatusBar(activity, dark);
    
                        break;
    
                    case RomUtils.AvailableRomType.ANDROID_NATIVE:
                        setAndroidNativeLightStatusBar(activity, dark);
                        break;
    
                }
            }
        }
    
    
        /**
         * 小米修改状态栏字体
         * @param activity
         * @param dark
         * @return
         */
        public static boolean MIUISetStatusBarLightMode(Activity activity, boolean dark) {
            boolean result = false;
            Window window = activity.getWindow();
            if (window != null) {
                Class clazz = window.getClass();
                try {
                    int darkModeFlag = 0;
                    Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
                    Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
                    darkModeFlag = field.getInt(layoutParams);
                    Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
                    if (dark) {
                        extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
                    } else {
                        extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体
                    }
                    result = true;
    
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && RomUtils.isMiUIV7OrAbove()) {
                        //开发版 7.7.13 及以后版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上
                        if (dark) {
                            activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
                        } else {
                            activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
                        }
                    }
                } catch (Exception e) {
    
                }
            }
            return result;
        }
    
        /**
         * 魅族修改字体颜色
         * @param activity
         * @param dark
         * @return
         */
        private static boolean setFlymeLightStatusBar(Activity activity, boolean dark) {
            boolean result = false;
            if (activity != null) {
                try {
                    WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
                    Field darkFlag = WindowManager.LayoutParams.class
                            .getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
                    Field meizuFlags = WindowManager.LayoutParams.class
                            .getDeclaredField("meizuFlags");
                    darkFlag.setAccessible(true);
                    meizuFlags.setAccessible(true);
                    int bit = darkFlag.getInt(null);
                    int value = meizuFlags.getInt(lp);
                    if (dark) {
                        value |= bit;
                    } else {
                        value &= ~bit;
                    }
                    meizuFlags.setInt(lp, value);
                    activity.getWindow().setAttributes(lp);
                    result = true;
                } catch (Exception e) {
                }
            }
            return result;
        }
    
        /**
         * 谷歌原生方式修改
         * @param activity
         * @param dark
         */
        private static void setAndroidNativeLightStatusBar(Activity activity, boolean dark) {
            View decor = activity.getWindow().getDecorView();
            if (dark) {
                decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
            } else {
                decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            }
        }
    
        /**
         * 设置状态栏透明,启用全屏模式
         * @param activity
         */
        @TargetApi(19)
        public static void transparencyBar(Activity activity) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Window window = activity.getWindow();
                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                window.setStatusBarColor(Color.TRANSPARENT);
                window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
    
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                Window window = activity.getWindow();
                window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
                        WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            }
        }
    
    
    }
    /**
     * Class to manage status and navigation bar tint effects when using KitKat
     * translucent system UI modes.
     * 修改状态栏颜色的辅助类 
     *
     */
    public class SystemBarTintManager {
    
        static {
            // Android allows a system property to override the presence of the navigation bar.
            // Used by the emulator.
            // See https://github.com/android/platform_frameworks_base/blob/master/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#L1076
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                try {
                    Class c = Class.forName("android.os.SystemProperties");
                    Method m = c.getDeclaredMethod("get", String.class);
                    m.setAccessible(true);
                    sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys");
                } catch (Throwable e) {
                    sNavBarOverride = null;
                }
            }
        }
    
    
        /**
         * The default system bar tint color value.
         */
        public static final int DEFAULT_TINT_COLOR = 0x99000000;
    
        private static String sNavBarOverride;
    
        private final SystemBarConfig mConfig;
        private boolean mStatusBarAvailable;
        private boolean mNavBarAvailable;
        private boolean mStatusBarTintEnabled;
        private boolean mNavBarTintEnabled;
        private View mStatusBarTintView;
        private View mNavBarTintView;
    
        /**
         * Constructor. Call this in the host activity onCreate method after its
         * content view has been set. You should always create new instances when
         * the host activity is recreated.
         *
         * @param activity The host activity.
         */
        @TargetApi(19)
        public SystemBarTintManager(Activity activity) {
    
            Window win = activity.getWindow();
            ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                // check theme attrs
                int[] attrs = {android.R.attr.windowTranslucentStatus,
                        android.R.attr.windowTranslucentNavigation};
                TypedArray a = activity.obtainStyledAttributes(attrs);
                try {
                    mStatusBarAvailable = a.getBoolean(0, false);
                    mNavBarAvailable = a.getBoolean(1, false);
                } finally {
                    a.recycle();
                }
    
                // check window flags
                WindowManager.LayoutParams winParams = win.getAttributes();
                int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
                if ((winParams.flags & bits) != 0) {
                    mStatusBarAvailable = true;
                }
                bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
                if ((winParams.flags & bits) != 0) {
                    mNavBarAvailable = true;
                }
            }
    
            mConfig = new SystemBarConfig(activity, mStatusBarAvailable, mNavBarAvailable);
            // device might not have virtual navigation keys
            if (!mConfig.hasNavigtionBar()) {
                mNavBarAvailable = false;
            }
    
            if (mStatusBarAvailable) {
                setupStatusBarView(activity, decorViewGroup);
            }
            if (mNavBarAvailable) {
                setupNavBarView(activity, decorViewGroup);
            }
    
        }
    
        /**
         * Enable tinting of the system status bar.
         *
         * If the platform is running Jelly Bean or earlier, or translucent system
         * UI modes have not been enabled in either the theme or via window flags,
         * then this method does nothing.
         *
         * @param enabled True to enable tinting, false to disable it (default).
         */
        public void setStatusBarTintEnabled(boolean enabled) {
            mStatusBarTintEnabled = enabled;
            if (mStatusBarAvailable) {
                mStatusBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
            }
        }
    
        /**
         * Enable tinting of the system navigation bar.
         *
         * If the platform does not have soft navigation keys, is running Jelly Bean
         * or earlier, or translucent system UI modes have not been enabled in either
         * the theme or via window flags, then this method does nothing.
         *
         * @param enabled True to enable tinting, false to disable it (default).
         */
        public void setNavigationBarTintEnabled(boolean enabled) {
            mNavBarTintEnabled = enabled;
            if (mNavBarAvailable) {
                mNavBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
            }
        }
    
        /**
         * Apply the specified color tint to all system UI bars.
         *
         * @param color The color of the background tint.
         */
        public void setTintColor(int color) {
            setStatusBarTintColor(color);
            setNavigationBarTintColor(color);
        }
    
        /**
         * Apply the specified drawable or color resource to all system UI bars.
         *
         * @param res The identifier of the resource.
         */
        public void setTintResource(int res) {
            setStatusBarTintResource(res);
            setNavigationBarTintResource(res);
        }
    
        /**
         * Apply the specified drawable to all system UI bars.
         *
         * @param drawable The drawable to use as the background, or null to remove it.
         */
        public void setTintDrawable(Drawable drawable) {
            setStatusBarTintDrawable(drawable);
            setNavigationBarTintDrawable(drawable);
        }
    
        /**
         * Apply the specified alpha to all system UI bars.
         *
         * @param alpha The alpha to use
         */
        public void setTintAlpha(float alpha) {
            setStatusBarAlpha(alpha);
            setNavigationBarAlpha(alpha);
        }
    
        /**
         * Apply the specified color tint to the system status bar.
         *
         * @param color The color of the background tint.
         */
        public void setStatusBarTintColor(int color) {
            if (mStatusBarAvailable) {
                mStatusBarTintView.setBackgroundColor(color);
            }
        }
    
        /**
         * Apply the specified drawable or color resource to the system status bar.
         *
         * @param res The identifier of the resource.
         */
        public void setStatusBarTintResource(int res) {
            if (mStatusBarAvailable) {
                mStatusBarTintView.setBackgroundResource(res);
            }
        }
    
        /**
         * Apply the specified drawable to the system status bar.
         *
         * @param drawable The drawable to use as the background, or null to remove it.
         */
        @SuppressWarnings("deprecation")
        public void setStatusBarTintDrawable(Drawable drawable) {
            if (mStatusBarAvailable) {
                mStatusBarTintView.setBackgroundDrawable(drawable);
            }
        }
    
        /**
         * Apply the specified alpha to the system status bar.
         *
         * @param alpha The alpha to use
         */
        @TargetApi(11)
        public void setStatusBarAlpha(float alpha) {
            if (mStatusBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                mStatusBarTintView.setAlpha(alpha);
            }
        }
    
        /**
         * Apply the specified color tint to the system navigation bar.
         *
         * @param color The color of the background tint.
         */
        public void setNavigationBarTintColor(int color) {
            if (mNavBarAvailable) {
                mNavBarTintView.setBackgroundColor(color);
            }
        }
    
        /**
         * Apply the specified drawable or color resource to the system navigation bar.
         *
         * @param res The identifier of the resource.
         */
        public void setNavigationBarTintResource(int res) {
            if (mNavBarAvailable) {
                mNavBarTintView.setBackgroundResource(res);
            }
        }
    
        /**
         * Apply the specified drawable to the system navigation bar.
         *
         * @param drawable The drawable to use as the background, or null to remove it.
         */
        @SuppressWarnings("deprecation")
        public void setNavigationBarTintDrawable(Drawable drawable) {
            if (mNavBarAvailable) {
                mNavBarTintView.setBackgroundDrawable(drawable);
            }
        }
    
        /**
         * Apply the specified alpha to the system navigation bar.
         *
         * @param alpha The alpha to use
         */
        @TargetApi(11)
        public void setNavigationBarAlpha(float alpha) {
            if (mNavBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                mNavBarTintView.setAlpha(alpha);
            }
        }
    
        /**
         * Get the system bar configuration.
         *
         * @return The system bar configuration for the current device configuration.
         */
        public SystemBarConfig getConfig() {
            return mConfig;
        }
    
        /**
         * Is tinting enabled for the system status bar?
         *
         * @return True if enabled, False otherwise.
         */
        public boolean isStatusBarTintEnabled() {
            return mStatusBarTintEnabled;
        }
    
        /**
         * Is tinting enabled for the system navigation bar?
         *
         * @return True if enabled, False otherwise.
         */
        public boolean isNavBarTintEnabled() {
            return mNavBarTintEnabled;
        }
    
        private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {
            mStatusBarTintView = new View(context);
            LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());
            params.gravity = Gravity.TOP;
            if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {
                params.rightMargin = mConfig.getNavigationBarWidth();
            }
            mStatusBarTintView.setLayoutParams(params);
            mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
            mStatusBarTintView.setVisibility(View.GONE);
            decorViewGroup.addView(mStatusBarTintView);
        }
    
        private void setupNavBarView(Context context, ViewGroup decorViewGroup) {
            mNavBarTintView = new View(context);
            LayoutParams params;
            if (mConfig.isNavigationAtBottom()) {
                params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getNavigationBarHeight());
                params.gravity = Gravity.BOTTOM;
            } else {
                params = new LayoutParams(mConfig.getNavigationBarWidth(), LayoutParams.MATCH_PARENT);
                params.gravity = Gravity.RIGHT;
            }
            mNavBarTintView.setLayoutParams(params);
            mNavBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
            mNavBarTintView.setVisibility(View.GONE);
            decorViewGroup.addView(mNavBarTintView);
        }
    
        /**
         * Class which describes system bar sizing and other characteristics for the current
         * device configuration.
         *
         */
        public static class SystemBarConfig {
    
            private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";
            private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height";
            private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape";
            private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width";
            private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar";
    
            private final boolean mTranslucentStatusBar;
            private final boolean mTranslucentNavBar;
            private final int mStatusBarHeight;
            private final int mActionBarHeight;
            private final boolean mHasNavigationBar;
            private final int mNavigationBarHeight;
            private final int mNavigationBarWidth;
            private final boolean mInPortrait;
            private final float mSmallestWidthDp;
    
            private SystemBarConfig(Activity activity, boolean translucentStatusBar, boolean traslucentNavBar) {
                Resources res = activity.getResources();
                mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
                mSmallestWidthDp = getSmallestWidthDp(activity);
                mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME);
                mActionBarHeight = getActionBarHeight(activity);
                mNavigationBarHeight = getNavigationBarHeight(activity);
                mNavigationBarWidth = getNavigationBarWidth(activity);
                mHasNavigationBar = (mNavigationBarHeight > 0);
                mTranslucentStatusBar = translucentStatusBar;
                mTranslucentNavBar = traslucentNavBar;
            }
    
            @TargetApi(14)
            private int getActionBarHeight(Context context) {
                int result = 0;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    TypedValue tv = new TypedValue();
                    context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
                    result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics());
                }
                return result;
            }
    
            @TargetApi(14)
            private int getNavigationBarHeight(Context context) {
                Resources res = context.getResources();
                int result = 0;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    if (hasNavBar(context)) {
                        String key;
                        if (mInPortrait) {
                            key = NAV_BAR_HEIGHT_RES_NAME;
                        } else {
                            key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME;
                        }
                        return getInternalDimensionSize(res, key);
                    }
                }
                return result;
            }
    
            @TargetApi(14)
            private int getNavigationBarWidth(Context context) {
                Resources res = context.getResources();
                int result = 0;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    if (hasNavBar(context)) {
                        return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME);
                    }
                }
                return result;
            }
    
            @TargetApi(14)
            private boolean hasNavBar(Context context) {
                Resources res = context.getResources();
                int resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android");
                if (resourceId != 0) {
                    boolean hasNav = res.getBoolean(resourceId);
                    // check override flag (see static block)
                    if ("1".equals(sNavBarOverride)) {
                        hasNav = false;
                    } else if ("0".equals(sNavBarOverride)) {
                        hasNav = true;
                    }
                    return hasNav;
                } else { // fallback
                    return !ViewConfiguration.get(context).hasPermanentMenuKey();
                }
            }
    
            private int getInternalDimensionSize(Resources res, String key) {
                int result = 0;
                int resourceId = res.getIdentifier(key, "dimen", "android");
                if (resourceId > 0) {
                    result = res.getDimensionPixelSize(resourceId);
                }
                return result;
            }
    
            @SuppressLint("NewApi")
            private float getSmallestWidthDp(Activity activity) {
                DisplayMetrics metrics = new DisplayMetrics();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
                } else {
                    // TODO this is not correct, but we don't really care pre-kitkat
                    activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
                }
                float widthDp = metrics.widthPixels / metrics.density;
                float heightDp = metrics.heightPixels / metrics.density;
                return Math.min(widthDp, heightDp);
            }
    
            /**
             * Should a navigation bar appear at the bottom of the screen in the current
             * device configuration? A navigation bar may appear on the right side of
             * the screen in certain configurations.
             *
             * @return True if navigation should appear at the bottom of the screen, False otherwise.
             */
            public boolean isNavigationAtBottom() {
                return (mSmallestWidthDp >= 600 || mInPortrait);
            }
    
            /**
             * Get the height of the system status bar.
             *
             * @return The height of the status bar (in pixels).
             */
            public int getStatusBarHeight() {
                return mStatusBarHeight;
            }
    
            /**
             * Get the height of the action bar.
             *
             * @return The height of the action bar (in pixels).
             */
            public int getActionBarHeight() {
                return mActionBarHeight;
            }
    
            /**
             * Does this device have a system navigation bar?
             *
             * @return True if this device uses soft key navigation, False otherwise.
             */
            public boolean hasNavigtionBar() {
                return mHasNavigationBar;
            }
    
            /**
             * Get the height of the system navigation bar.
             *
             * @return The height of the navigation bar (in pixels). If the device does not have
             * soft navigation keys, this will always return 0.
             */
            public int getNavigationBarHeight() {
                return mNavigationBarHeight;
            }
    
            /**
             * Get the width of the system navigation bar when it is placed vertically on the screen.
             *
             * @return The width of the navigation bar (in pixels). If the device does not have
             * soft navigation keys, this will always return 0.
             */
            public int getNavigationBarWidth() {
                return mNavigationBarWidth;
            }
    
            /**
             * Get the layout inset for any system UI that appears at the top of the screen.
             *
             * @param withActionBar True to include the height of the action bar, False otherwise.
             * @return The layout inset (in pixels).
             */
            public int getPixelInsetTop(boolean withActionBar) {
                return (mTranslucentStatusBar ? mStatusBarHeight : 0) + (withActionBar ? mActionBarHeight : 0);
            }
    
            /**
             * Get the layout inset for any system UI that appears at the bottom of the screen.
             *
             * @return The layout inset (in pixels).
             */
            public int getPixelInsetBottom() {
                if (mTranslucentNavBar && isNavigationAtBottom()) {
                    return mNavigationBarHeight;
                } else {
                    return 0;
                }
            }
    
            /**
             * Get the layout inset for any system UI that appears at the right of the screen.
             *
             * @return The layout inset (in pixels).
             */
            public int getPixelInsetRight() {
                if (mTranslucentNavBar && !isNavigationAtBottom()) {
                    return mNavigationBarWidth;
                } else {
                    return 0;
                }
            }
    
        }
    

     

    /**
     * 设置状态栏时候 怼不通机型进行适配
     */
    public class RomUtils {
    
        class AvailableRomType {
            public static final int MIUI = 1;
            public static final int FLYME = 2;
            public static final int ANDROID_NATIVE = 3;
            public static final int NA = 4;
        }
    
        public static int getLightStatusBarAvailableRomType() {
            //开发版 7.7.13 及以后版本采用了系统API,旧方法无效但不会报错
            if (isMiUIV7OrAbove()) {
                return AvailableRomType.ANDROID_NATIVE;
            }
    
            if (isMiUIV6OrAbove()) {
                return AvailableRomType.MIUI;
            }
    
            if (isFlymeV4OrAbove()) {
                return AvailableRomType.FLYME;
            }
    
            if (isAndroidMOrAbove()) {
                return AvailableRomType.ANDROID_NATIVE;
            }
    
            return AvailableRomType.NA;
        }
    
        //Flyme V4的displayId格式为 [Flyme OS 4.x.x.xA]
        //Flyme V5的displayId格式为 [Flyme 5.x.x.x beta]
        private static boolean isFlymeV4OrAbove() {
            String displayId = Build.DISPLAY;
            if (!TextUtils.isEmpty(displayId) && displayId.contains("Flyme")) {
                String[] displayIdArray = displayId.split(" ");
                for (String temp : displayIdArray) {
                    //版本号4以上,形如4.x.
                    if (temp.matches("^[4-9]\\.(\\d+\\.)+\\S*")) {
                        return true;
                    }
                }
            }
            return false;
        }
    
        //Android Api 23以上
        private static boolean isAndroidMOrAbove() {
            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
        }
    
        private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
    
        private static boolean isMiUIV6OrAbove() {
            try {
                final Properties properties = new Properties();
                properties.load(new FileInputStream(new File(Environment.getRootDirectory(), "build.prop")));
                String uiCode = properties.getProperty(KEY_MIUI_VERSION_CODE, null);
                if (uiCode != null) {
                    int code = Integer.parseInt(uiCode);
                    return code >= 4;
                } else {
                    return false;
                }
    
            } catch (final Exception e) {
                return false;
            }
    
        }
    
        static boolean isMiUIV7OrAbove() {
            try {
                final Properties properties = new Properties();
                properties.load(new FileInputStream(new File(Environment.getRootDirectory(), "build.prop")));
                String uiCode = properties.getProperty(KEY_MIUI_VERSION_CODE, null);
                if (uiCode != null) {
                    int code = Integer.parseInt(uiCode);
                    return code >= 5;
                } else {
                    return false;
                }
    
            } catch (final Exception e) {
                return false;
            }
    
        }
    
    }

    好了 ,也就这些了 。  自己可以复制出去试试就好了。

    总结:

    一般情况首页的那几个Fragment 使用的沉浸式较多一些:透明状态栏+黑色      或者透明状态栏+白色

    业务模块中: 可以统一设置状态栏颜色,以及字体颜色。

    展开全文
  • Android 沉浸式状态栏攻略 让你的状态栏变色吧

    万次阅读 多人点赞 2015-09-22 09:21:03
    一、概述近期注意到QQ新版使用了沉浸式状态栏,ok,先声明一下:本篇博客效果下图:关于这个状态栏变色到底叫「Immersive Mode」/「Translucent Bars」有兴趣可以去 为什么在国内会有很多用户把 「透明

    转载请标明出处:
    http://blog.csdn.net/lmj623565791/article/details/48649563
    本文出自:【张鸿洋的博客】

    一、概述

    近期注意到QQ新版使用了沉浸式状态栏,ok,先声明一下:本篇博客效果下图:

    20150922091410975

    关于这个状态栏变色到底叫「Immersive Mode」/「Translucent Bars」有兴趣可以去 为什么在国内会有很多用户把 「透明栏」(Translucent Bars)称作 「沉浸式顶栏」?上面了解了解,请勿指点我说的博文标题起得不对,thx。

    恩,接下来正题。

    首先只有大于等于4.4版本支持这个半透明状态栏的效果,但是4.4和5.0的显示效果有一定的差异,所有本篇博文内容为:

    • 如何实现半透明状态栏效果在大于4.4版本之上。
    • 如何让4.4的效果与5.0的效果尽可能一致。

    看了不少参考文章,都介绍到这个库,大家可以了解:SystemBarTint

    不过本篇博文并未基于此库,自己想了个hack,对于此库源码有空再看了。


    二、效果图

    先贴下效果图,以便和实现过程中做下对比

    • 4.4 模拟器

    20150922091443734

    • 5.x 真机

    20150922091513487

    [new]贴个如果顶部是图片的效果图,其实是一样的,为了方便我就放侧栏的顶部了。

    lalala.gif

    稍等,csdn图片服务器异常…

    ok,有了效果图之后就开始看实现了。


    三、实现半透明状态栏

    因为本例使用了NavigationView,所以布局代码稍多,当然如果你不需要,可以自己进行筛减。

    注意引入相关依赖:

     compile 'com.android.support:appcompat-v7:22.2.1'
     compile 'com.android.support:support-v4:22.2.1'
     compile 'com.android.support:design:22.2.0'

    (一)colors.xml 和 styles.xml

    首先我们定义几个颜色:

    res/values/color.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <color name="primary">#FF03A9F4</color>
        <color name="primary_dark">#FF0288D1</color>
        <color name="status_bar_color">@color/primary_dark</color>
    </resources>

    下面定义几个styles.xml

    注意文件夹的路径:

    values/styles.xml

    <resources>
        <style name="BaseAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/primary</item>
            <item name="colorPrimaryDark">@color/primary_dark</item>
            <item name="colorAccent">#FF4081</item>
        </style>
    
        <!-- Base application theme. -->
        <style name="AppTheme" parent="@style/BaseAppTheme">
        </style>
    </resources>

    values-v19

    <resources>
    
        <style name="AppTheme" parent="@style/BaseAppTheme">
            <item name="android:windowTranslucentStatus">true</item>
        </style>
    </resources>
    

    ok,这个没撒说的。注意我们的主题是基于NoActionBar的,android:windowTranslucentStatus这个属性是v19开始引入的。

    (二)布局文件

    activity_main.xml

    <android.support.v4.widget.DrawerLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
    
    
        <LinearLayout
            android:id="@+id/id_main_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/id_toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="?attr/colorPrimary"
                android:fitsSystemWindows="true"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
    
    
            <TextView
                android:id="@+id/id_tv_content"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:gravity="center"
                android:text="HelloWorld"
                android:textSize="30sp"/>
        </LinearLayout>
    
    
        <android.support.design.widget.NavigationView
            android:id="@+id/id_nv_menu"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:fitsSystemWindows="true"
            app:headerLayout="@layout/header_just_username"
            app:menu="@menu/menu_drawer"
            />
    </android.support.v4.widget.DrawerLayout>
    

    DrawerLayout内部一个LinearLayout作为内容区域,一个NavigationView作为菜单。
    注意下Toolbar的高度设置为wrap_content。

    然后我们的NavigationView中又依赖一个布局文件和一个menu的文件。

    header_just_username.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:layout_width="match_parent"
                    android:layout_height="192dp"
                    android:background="?attr/colorPrimaryDark"
                    android:orientation="vertical"
                    android:padding="16dp"
                    android:fitsSystemWindows="true"
                    android:theme="@style/ThemeOverlay.AppCompat.Dark">
    
        <TextView
            android:id="@+id/id_link"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="16dp"
            android:text="http://blog.csdn.net/lmj623565791"/>
    
        <TextView
            android:id="@+id/id_username"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/id_link"
            android:text="Zhang Hongyang"/>
    
        <ImageView
            android:layout_width="72dp"
            android:layout_height="72dp"
            android:layout_above="@id/id_username"
            android:layout_marginBottom="16dp"
            android:src="@mipmap/ic_launcher"/>
    
    
    </RelativeLayout>

    menu的文件就不贴了,更加详细的可以去参考Android 自己实现 NavigationView [Design Support Library(1)]

    大体看完布局文件以后,有几个点要特别注意:

    • ToolBar高度设置为wrap_content
    • ToolBar添加属性android:fitsSystemWindows="true"
    • header_just_username.xml的跟布局RelativeLayout,添加属性android:fitsSystemWindows="true"

    android:fitsSystemWindows这个属性,主要是通过调整当前设置这个属性的view的padding去为我们的status_bar留下空间。

    根据上面的解释,如果你不写,那么状态栏和Toolbar就会有挤一块的感觉了,类似会这样:

    20150922091617868

    ok,最后看下代码。

    (三)Activity的代码

    package com.zhy.colorfulstatusbar;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    
    public class MainActivity extends AppCompatActivity
    {
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.id_toolbar);
            setSupportActionBar(toolbar);
            //StatusBarCompat.compat(this, getResources().getColor(R.color.status_bar_color));
            //StatusBarCompat.compat(this);
        }
    
    }
    

    没撒说的,就是setSupportActionBar。

    那么现在4.4的效果图是:

    20150922091636754

    其实还不错,有个渐变的效果。

    现在5.x的效果:

    20150922094815752

    可以看到5.x默认并非是一个渐变的效果,类似是一个深一点的颜色。

    在看看我们md的规范

    20150427034747930

    状态栏应该是一个比Toolbar背景色,稍微深一点的颜色。

    这么看来,我们还是有必要去为4.4做点适配工作,让其竟可能和5.x显示效果一致,或者说尽可能符合md的规范。


    四、调整4.4的显示方案

    那么问题来了?如何做呢?

    咱们这么看,4.4之后加入windowTranslucentStatus的属性之后,也就是我们可以用到状态栏的区域了。

    既然我们可以用到这块区域,那么我们只要在根布局去设置一个与状态栏等高的View,设置背景色为我们期望的颜色就可以了。

    于是有了以下的代码:

    package com.zhy.colorfulstatusbar;
    
    import android.annotation.TargetApi;
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Color;
    import android.os.Build;
    import android.view.View;
    import android.view.ViewGroup;
    
    /**
     * Created by zhy on 15/9/21.
     */
    public class StatusBarCompat
    {
        private static final int INVALID_VAL = -1;
        private static final int COLOR_DEFAULT = Color.parseColor("#20000000");
    
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        public static void compat(Activity activity, int statusColor)
        {
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
            {
                if (statusColor != INVALID_VAL)
                {
                    activity.getWindow().setStatusBarColor(statusColor);
                }
                return;
            }
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
            {
                int color = COLOR_DEFAULT;
                ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
                if (statusColor != INVALID_VAL)
                {
                    color = statusColor;
                }
                View statusBarView = new View(activity);
                ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        getStatusBarHeight(activity));
                statusBarView.setBackgroundColor(color);
                contentView.addView(statusBarView, lp);
            }
    
        }
    
        public static void compat(Activity activity)
        {
            compat(activity, INVALID_VAL);
        }
    
    
        public static int getStatusBarHeight(Context context)
        {
            int result = 0;
            int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
            if (resourceId > 0)
            {
                result = context.getResources().getDimensionPixelSize(resourceId);
            }
            return result;
        }
    }
    

    代码的思路很简单,根据Activity找到android.R.content,在其中添加一个View(高度为statusbarHeight,背景色为我们设置的颜色,默认为半透明的黑色)。

    那么只需要在Activity里面去写上:

    StatusBarCompat.compat(this);

    就可以了。

    如果你希望自己设置状态看颜色,那么就用这个方法:

    StatusBarCompat.compat(this, getResources().getColor(R.color.status_bar_color));

    这样的话我们就解决了4.4到5.x的适配问题,一行代码解决,感觉还是不错的。

    最后提一下,对于5.0由于提供了setStatusBarColor去设置状态栏颜色,但是这个方法不能在主题中设置windowTranslucentStatus属性。所以,可以编写一个value-v21文件夹,里面styles.xml写入:

    <resources>
        <!-- Base application theme. -->
        <style name="AppTheme" parent="@style/BaseAppTheme">
        </style>
    </resources>
    

    其实就是不要有windowTranslucentStatus属性。

    接下来,对于默认的效果就不测试了,参考上面的效果图。

    我们测试个设置状态栏颜色的,我们这里设置个红色。

    • 4.4 模拟器

    20150922091706192

    • 5.x 真机

    20150922091721370

    ok,这样就结束啦~~

    源码地址:https://github.com/hongyangAndroid/ColorfulStatusBar


    欢迎关注我的微博:
    http://weibo.com/u/3165018720


    群号:463081660,欢迎入群

    微信公众号:hongyangAndroid
    (欢迎关注,第一时间推送博文信息)
    1422600516_2905.jpg

    参考

    展开全文
  • Android沉浸式状态栏(透明状态栏)最佳实现

    万次阅读 多人点赞 2016-12-06 16:58:39
    Android沉浸式状态栏(透明状态栏)最佳实现 在Android4.4之前,我们的应用没法改变手机的状态栏颜色,当我们打开应用时,会出现上图中左侧的画面,在屏幕的顶部有一条黑色的状态栏,和应用的风格非常不协调;为了...

    Android沉浸式状态栏(透明状态栏)最佳实现

    这里写图片描述
    在Android4.4之前,我们的应用没法改变手机的状态栏颜色,当我们打开应用时,会出现上图中左侧的画面,在屏幕的顶部有一条黑色的状态栏,和应用的风格非常不协调;为了提供更好的界面交互,google在Android4.4以后提供了设置沉浸式状态栏的方法,对于沉浸式状态栏这个名字存在争议,我们不做讨论,实际的效果其实就是透明的状态栏,然后在状态栏的位置显示我们自定义的颜色,通常为应用的actionbar的颜色,或者是将应用的整体的一张图片也占据到状态栏中,如下图所示:
    这里写图片描述

    由于这种透明的状态栏是在Android4.4以后才出现的,所以我们需要为4.4以上的版本做适配,方法有两种,一种是在资源文件(style)中设置,一个是在代码中设置。

    在资源文件中设置透明状态栏

    首先,我们先在values下的style中加入如下代码:

        <!-- Base application theme. -->
        <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
        </style>
    
        <style name="AppTheme.Main" parent="AppTheme" />

    AppTheme.Main是我们要设置给activity的主题,它应该继承于AppTheme.NoActionBar,然后
    我们在values-v19中加入同样的AppTheme.Main,如下所示:

        <style name="AppTheme.Main" parent="AppTheme.NoActionBar">
            <item name="android:windowTranslucentStatus">true</item>
        </style>

    然后运行程序,效果如图所示:
    这里写图片描述
    图片中我们发现,虽然我们实现了透明的状态栏,但是上边的文字和状态栏的信息重叠了。为了修复这个问题,我们应该在布局文件的根布局中加入android:fitsSystemWindows=”true” 就可以了,加入后效果如下:
    这里写图片描述
    应用的文字和系统显示的文字错开了,这也是我们最终的显示效果

    需要注意的几点:

    1. 为Android4.4+适配的同时,不要忘了在values的style.xml中加入同名的自定义style,不然4.4以下会报错
    2. 不要忘记在布局文件中加入 android:fitsSystemWindows=”true”,不然布局内容会和状态栏内容重叠
    3. 在Android5.0中,透明标题的效果和4.4中有所不同,但是实现方法相同,我们可以不必为5.0+单独适配,同时5.0+的版本提供了新的API android:statusBarColor,可以用来单独设置状态栏的颜色,但是这种方法不适用于我们例子中的图片占据状态栏,它适用于纯色的状态栏,并且它应该放到value-v21文件夹中

      上边的例子中,我们只设置了一个图片,使其占据了状态栏。但是我们平常见到更多的可能不是这种,而且带actionbar的情况,如下所示:
      这里写图片描述
      在上图中,存在一个actionbar,然后状态栏的颜色与其相同,接下来我们来实现这种效果。

    style文件不用改变,我们需要在布局文件中加入一个toolbar,代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorAccent"
        android:orientation="vertical"
        tools:context="com.zephyr.musicapp.MainActivity">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:fitsSystemWindows="true"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/AppTheme.PopupOverlay"/>
    
    </LinearLayout>
    然后在activity中
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);

    在一个LinearLayout中包含了一个toolbar,和第一个例子相比,我们把android:fitsSystemWindows=”true”加在了Toolbar上边,而不是LinearLayout中,如果把android:fitsSystemWindows=”true”放到LinearLayout中,会出现下边的效果:
    这里写图片描述
    虽然状态栏透明了,但是颜色却和根布局的颜色相同而不是toolbar,这样显然不行,如果我们把android:fitsSystemWindows=”true”放到toolbar中就可以实现我们的效果,如下图所示:
    这里写图片描述

    在这里,我们还需要特别注意一个地方,那就是在设置toolbar高度的时候,应该设置成wrap_content,不然也没法实现我们的效果,比如我把高度固定为50dp,效果如下:
    这里写图片描述
    虽然占据了状态栏,但是toolbar的高度明显不够了,效果很不好。

    在Android5.0以后,增加了新的API android:statusBarColor 用于设置状态栏的颜色,同时以前的windowTranslucentStatus也是对它有效的,所以如果想通过新的API设置状态栏颜色的话,首先应该将windowTranslucentStatus设置为false,不然是没有效果的。

    以上就是通过资源文件设置透明状态栏的方法。

    代码中设置透明状态栏

    在代码中设置透明状态栏的方法也很简单,思路就是首先通过 WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS设置当前window为透明状态栏,这样标题栏就可以占据状态栏了,但是会出现布局中的内容和状态栏的内容重叠的问题,为了解决这个问题,我们应该获得状态栏的高度,然后设置标题栏的paddingTop为状态栏的高度,这样就可以实现透明效果的标题栏的,代码如下:

     protected void setImmerseLayout(View view) {// view为标题栏
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                Window window = getWindow();
                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                int statusBarHeight = getStatusBarHeight(this.getBaseContext());
                view.setPadding(0, statusBarHeight, 0, 0);
            }
        }
    
        public int getStatusBarHeight(Context context) {
            int result = 0;
            int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen",
                    "android");
            if (resourceId > 0) {
                result = context.getResources().getDimensionPixelSize(resourceId);
            }
            return result;
        }

    fitSystemWindows属性:
    官方描述:
    Boolean internal attribute to adjust view layout based on system windows such as the status bar. If true, adjusts the padding of this view to leave space for the system windows. Will only take effect if this view is in a non-embedded activity.


    补充:
    当为纯色actionbar的情况下,我们将toolbar的高度设为wrap_content,并且将fitsSystemWindows=“true”参数设置到了toolbar上,这样虽然实现了4.4版本的沉浸效果,但是却不能有效的适配5.0及以上的版本,所以做出以上修改。
    在4.4版本上:
    1. 我们将根布局的背景颜色设置成和toolbar一样的,并且设fitsSystemWindows为true。
    2. toolbar的fitsSystemWindows属性去掉,并且高度设置为?attr/actionBarSize
    3. 在toolbar下增加一个子布局,颜色设置为white,这样就可以在4.4及5.0以上实现带actionbar的沉浸式布局

    2017.12.14更新:
    使用纯色actionbar的时候,可以使用容器包裹toolbar,只设置容器 fitsSystemWindows为true。由于fitsSystemWindows属性本质上是给当前控件设置了一个padding,所以我们设置到根布局的话,会导致状态栏是透明的,并且和窗口背景一样,和toolbar背景不同。如果我们设置给toolbar,则会由于padding的存在,导致toolbar的内容下移。所以我们选择使用LinearLayout包裹toolbar,并将toolbar的背景等属性设置在appbarlayout上就可以完美实现效果,代码:

     <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:fitsSystemWindows="true"
        android:orientation="vertical">
    
        <android.support.v7.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:title="Login"/>
    </LinearLayout>
    
    展开全文
  • Android 沉浸式状态栏状态栏一体化、透明状态栏、仿iOS透明状态栏  http://blog.csdn.net/jdsjlzx/article/details/50437779 注:状态栏的字体颜色位白色, 如果状态栏背景为白色,上面的博客已经解决了。...
  • 沉浸式状态栏:,状态栏隐藏,在手指做了相关操作后,状态栏显示出来,例如视频播放器,在播放视频时是隐藏状态栏的,但是点击屏幕的时候,状态栏会显示出来,再例如文本阅读器,在阅读的时候是全屏的,然后从屏幕...
  • 1.实现透明状态栏 安卓4.4以上才可以实现透明状态栏,具体代码如下: Window window = activity.getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 实现透明状态栏会默认把应用的...
  • 看了网上介绍,关于沉浸式状态栏大概有几种,透明状态栏,变色状态栏,沉浸式状态栏。变色状态栏大概只是通用说法,无论沉浸式还是透明的 都可以实现状态栏的变色。这里就不再介绍。 1,透明状态栏顾名思义就是透明...
  • Android布局顶到状态栏or状态栏布局or沉浸式状态栏1.状态栏里面开始布局的设置主题&lt;style name="NoActionBar" parent="Theme.AppCompat.Light.DarkActionBar"&gt; &lt;item ...
  • Android 透明状态栏Android 透明状态栏实现平台设置所需要的颜色填满屏幕状态栏透明化Padding调整状态栏颜色文字颜色设置(可选)颜色填充任务完成! 最近在做毕业设计,想要实现沉浸式状态栏,在网上搜索了好多的...
  • 这是一个为Android App 设置状态栏的工具类, 可以在4.4及其以上系统中实现 沉浸式状态栏/状态栏变色,支持设置状态栏透明度,满足你司设计师的各种要求(雾)。 本着不重复造轮子的原则,在网上找到了一个工具类,...
  • Android 沉浸式状态栏的实现方法、状态栏透明的实现方法
  • Android 去掉状态栏 去掉标题栏 沉浸式状态栏 状态栏重叠 布局重叠 SystemBarTintManager systembartint-1.0.4
  • Android开发中,经常需要实现下图状态栏的效果,类似于沉浸式状态栏,但这里仅仅是讨论设置状态栏的颜色和状态栏上面文字、图标的颜色的方法。 Android 4.4(API 19)之后,就提供了修改状态栏颜色的方法,但是在 ...
  • 2.状态栏为背景图片效果 状态栏为图片效果.jpg 3.侧滑页面效果 侧滑页面效果.jpg 4.自定义渐变效果 自定义渐变效果.jpg 5.含ActionBar效果 含ActionBar效果.jpg 工具类 package 包名; import ...
  • 这是一个为Android App 设置状态栏的工具类, 可以在4.4及其以上系统中实现 沉浸式状态栏/状态栏变色,支持设置状态栏透明度,满足你司设计师的各种要求(雾)。 在此之前我写过一篇Android App 沉浸式状态栏解决方案...
  • 透明状态栏(沉浸式状态栏

    千次阅读 2016-01-25 23:23:07
    透明状态栏(沉浸式状态栏)透明状态栏(Translucate StatusBar)是android从4.4开始模仿ios推出的一种模式,他可以改变状态栏的颜色,使其更加的与自己的app样式所统一android 4.4推出的状态栏为透明样式,但会有一...
  • iOS 更改状态栏颜色和隐藏状态栏

    千次阅读 2018-09-11 15:39:58
    更改状态栏颜色 iOS7以后 状态栏的字体为黑色:UIStatusBarStyleDefault 状态栏的字体为白色:UIStatusBarStyleLightContent 解决方案 1、在info.plist中,将View controller-based status bar appearance 设为...
  • Android状态栏着色-透明状态栏

    千次阅读 2016-11-10 11:34:28
    最近项目上有需求 ,要求状态栏透明化 。还有需求是拖动状态栏标题一下的内容,标题栏的颜色要变化 。这里所谓的既是状态栏着色,也是我们经常听到的沉浸式状态栏,关于沉浸式的称呼网上也有很多吐槽的,这里就不做...
  • 做应用有时候我们需要界面是全屏显示的,也就是没有状态栏的,或者说修改状态栏的背景颜色,让整个屏幕的风格和界面保持一致的(沉浸式?),几行代码轻松搞定! 1、隐藏状态栏 在onCreate方法里面添加页面状态 ...
  • 这是一个为Android App 设置状态栏的工具类, 可以在4.4及其以上系统中实现 沉浸式状态栏/状态栏变色,支持设置状态栏透明度,满足你司设计师的各种要求(雾)。 在此之前我写过一篇Android App 沉浸式状态栏...
  • 版本要求 沉浸式状态栏效果是在android 4.4的时候出现...2.修改状态栏颜色为透明色,将标题栏扩展到状态栏下面,以达到沉浸式效果 需要注意的坑 1.需要注意的是状态栏的字体颜色  目前可实现沉浸式效果的状态栏...
  • 1.设置状态栏透明方法 public static void makeStatusBarTransparent(Activity activity) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { return; } Window windo...
  • 今天突然出现的问题,在状态栏左下角的搜索框搜索OneNote没有任何反应,对,就是这个地方。 最后在另一篇博客上找到了答案,那篇博客也是在知乎找到的答案,虽然是用被人的方法解决了问题,但我还是打算记下来; 1...
  • 开发 App 的时候,常常需要做出沉浸式状态栏的效果。 在 iOS 平台,默认就是沉浸式的,View 的内容会从屏幕顶部开始绘制,若不进行处理,就会被状态栏覆盖。因此可以手动获取状态栏的高度,用样式留出状态栏的空间,...
  • 沉浸式状态栏究其根本就是将布局内容延伸到状态栏中,让状态栏覆盖在布局上或者隐藏。 实现 首先,要修改状态栏android版本至少要在4.4以上,并且在4.4是不能让状态栏透明的,只能达到一种半透明的阴影背景,而在5.x...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 42,732
精华内容 17,092
关键字:

状态栏