Android沉浸式状态栏以及浅色模式开发

来源:互联网 发布:小米2s数据恢复2 编辑:程序博客网 时间:2024/04/30 10:37

Android沉浸式状态栏开发从简入深

  • 转载请标明出处:http://blog.csdn.net/ccffvii/article/details/70919456
  • 本文推荐使用的框架:https://github.com/liyuhaolol/LightImmersionMode

前言

  • 现在已经迈入了Android 8.0的时代了,相信沉浸式状态栏的开发,已经不是一种选项,而是一种默认就应该去支持的东西了,但是相信大家在开发过程中肯定有遇到过这样或那样的问题,那么在这里我就带领大家,从最简单的方法入手,由浅入深的,深入学习一些各种沉浸式状态栏的开发方法。

  • Android在4.4开始支持沉浸式状态栏,而在4.4之前,状态栏只是纯黑色,无法控制。4.4引入了对沉浸式的支持,而5.0在4.4的基础上进一步引入了对状态栏进行操作的支持,最终在6.0上引入了对状态栏上文字颜色深浅的控制,解决了当状态栏颜色很浅时无法辨识上面的白色字体的情况。至此谷歌对Android状态栏支持接口算是更新告一段落了。那么好,下面就让我们开始跟随着版本号,一步一步的来看一下沉浸式状态栏的几种完成方法。

沉浸式状态栏的实现方法

  • 说好了从简单入手,那么先来个超级容易的小菜,如果你是高手,或者仅仅是着急使用框架,完成你的项目需求,你可以直接往后翻,翻到框架讲解那里。^-^,里面的每种方法,最终实现的效果都是一样的,只不过有好理解和难理解之分,难理解的当然效果更厉害一点。~~

1、配置状态栏默认颜色

  • 先无耻的盗个图,自己懒得做了,233
  • 看到图片相信大家已经明白什么意思了,状态栏的颜色在系统里的定义叫做colorPrimaryDark,所以只要修改这个颜色的色值就可以十分简单的修改状态栏的颜色了,仅仅需要把colorPrimaryDark改成跟你的TitleBar颜色一致,就可以十分容易的完成一个沉浸式的状态栏了!
<?xml version="1.0" encoding="utf-8"?><resources>    <color name="colorPrimaryDark">#303F9F</color></resources>

看到这里你肯定大呼坑爹,这哪是沉浸式开发啊,这就是改个颜色而已,是的你说没错,但是这个状态栏确实符合沉浸式的要求,这也是不可否认的。当然这么做局限性也很大,因为你并不能随意的修改默认的颜色,这么做必须保证你整个项目的头部View的颜色是可以与状态栏颜色衔接上的,否则就会很突兀。

2、沉浸式实现

  • 沉浸式的支持需要API LEVEL >= 19

完全沉浸式实现
- 实现的效果当然自然的分为了2种
非纯色沉浸状态
纯色沉浸状态

我们先来看一下非纯色状态栏的实现方法,因为这个十分容易。
非纯色沉浸状态
- 先来看一下效果图

  • 实现的效果基本就是将一个图片当作背景完整的嵌套入状态栏,具体实现方法呢,也很容易。在Activity
public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Window window = getWindow();        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);    }}

只需要将设置对应的Flag:FLAG_TRANSLUCENT_STATUS,将状态栏消除掉,让我们的View直接顶上去,这样就很简单的实现了非纯色的沉浸式状态,但是我们这篇文章其实主要研究的是纯色状态栏更好的开发方式,所以如果你需要的非纯色的状态栏,那么你看到这里就已经OK了!

纯色沉浸状态
-相信大家经过第一种方法开发以后,肯定会遇到自己控件跟状态栏重叠的情况
如图,此后为了演示明确,会把状态栏颜色和View的颜色区分开。

这时候一个理所当然的投机取巧的方法生成了,我把所有的View都向下移动一个状态栏的距离不就好了,于是第二种投机取巧的方法出现了。

  • 这里是第二种投机取巧的办法,跟修改colorPrimaryDark的意思差不多,就是把所有Layout中的View向下移动一个状态栏的距离
    实现的结构如图

经过我们大量的实践证明,状态栏的高度大概为24dp,所以我们就把子Layout设置属性android:layout_marginTop="24dp"就可以了。

<?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="match_parent"    android:background="#fed952">    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_marginTop="24dp">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="Hello!!!!!!!!!!!!!!!!!!!!!!!!!!!"            android:background="#303F9F"            android:textColor="#ffffff"/>    </RelativeLayout></RelativeLayout>

这样修改以后,我们的软件自然就很正常的显示了出来

这么做以后,相信你会有质疑了,这么做我所有的XML都要嵌套一个Layout,这是多么巨大的工作量,这么做多蠢啊。当然,这前两种方法,当然只是给你一个开胃菜,让你可以对沉浸式状态栏有个明确的认识,那么下面开始讲解大家正常开发的思路。

3、沉浸式+插入自定义StatusView实现

  • 正式的干货来了,大多数程序猿使用的其实是这种实现方法。

相信大家在搜索其他资料的时候,肯定听说过这个框架SystemBarTint
这个框架是对Android 4.4以后的系统很有效的实现纯色沉浸式的效果,使用方法我就不在本文里赘述了,大家可以点击下方转载链接去学习一下。
Android沉浸式状态栏SystemBarTint的使用方法
毕竟这个框架都已经是3,4年的框架了早就停止了更新,也没有对Android 5.0以后的新API进行支持,所以大家可以继续向下看,我给大家带来的新框架。
但是,这里我要学习一下这个框架的源码,理解其中的思路,就是沉浸式+插入自定义StatusView实现的过程

  • 结构思路:在我们的Layout外面,添加一个状态栏高度的View把我们的Layout压下来。
    结构图

我们将StatusView插入到我们的布局上方,这样就可以将我们的布局压下来了。
实现代码:
activity:

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Window window = getWindow();        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);        ViewGroup vg = (ViewGroup) getWindow().getDecorView();        View v = new View(this);        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,getStatusBarHeight());        v.setBackgroundColor(getResources().getColor(R.color.colorAccent));        v.setLayoutParams(params);        vg.addView(v);    }    public int getStatusBarHeight() {        int result = 0;        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");        if (resourceId > 0) {            result = getResources().getDimensionPixelSize(resourceId);        }        return result;    }}

activity_main.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="match_parent"    android:background="#fed952"    android:fitsSystemWindows="true"    android:clipToPadding="false">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="Hello!!!!!!!!!!!!!!!!!!!!!!!!!!!"            android:background="#303F9F"            android:textColor="#ffffff"/></RelativeLayout>
  • 在activity中我们操作步骤是这样的
    1、设置布局为沉浸式:
    Window window = getWindow();
    window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    2、得到ViewGroup
    ViewGroup vg = (ViewGroup) getWindow().getDecorView();
    3、创建StatusView
    View v = new View(this);
    ViewGroup.LayoutParams params = new ViewGroup
    .LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,getStatusBarHeight());
    v.setBackgroundColor(getResources().getColor(R.color.colorAccent));
    v.setLayoutParams(params);
    4、将StatusView添加至DecorView
    vg.addView(v);

  • 在布局中,我们要给父Layout添加两条属性,来确保布局可以正确的显示
    android:fitsSystemWindows="true"
    android:clipToPadding="false"
    上面的第一行代码fitsSystemWindows的作用是:
    让view可以根据系统窗口(如status bar)来调整自己的布局,如果值为true,就会调整view的paingding属性来给system windows留出空间。
    第二行代码clipToPadding 值的作用是:
    控件的绘制区域是否在padding里面的,默认是true,设置成false就表示可已在控件外面显示。
    显示的实际效果如图

  • 这么做以后是不是就不需要每个layout都进行嵌套了呢?节约了很多性能啊,毕竟Layout嵌套拖慢手机性能,但是有人也会提出来,每个layout都要添加两条属性,其实也很麻烦,这个我在使用的时候也发现了这个问题,所以我在自己写的框架里解决了这个问题,将java代码与xml的属性解耦了,大家不要担心,继续往下看吧

  • 看到了这里,大家是不是感觉有点懵逼呢?没关系,如果不太明白,就把代码拷贝到自己的AndroidStudio里实际运行感受一下,如果你都懂,那么给你大拇指,好棒棒哦~不过不要担心,最难的大山已经翻过去了,往后的都会很容易的!继续!

4、非沉浸式实现

  • 非沉浸式的支持需要API LEVEL >= 21
  • 看到这里我就害怕有人把沉浸式开发沉浸式状态开发弄混,这里强调一下沉浸式开发,如上文演示,一般使用背景颜色填充整个状态栏的开发思路才是沉浸式开发,而我们后来讲的插入StatusView,以及往后讲的非沉浸式开发,使用为非沉浸式的方法,来实现沉浸式的状态。这两个还是有点区别的,理解一下。
  • 可能是一年后,谷歌终于发现了,其实大家还是做纯色沉浸式状态栏的居多,但是用上文的方法实现,却十分的繁琐,所以,终于~谷歌在Android 5.0开放了对状态栏的代码控制

activity:

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Window window = getWindow();        window.setStatusBarColor(getResources().getColor(R.color.colorAccent));    }}
  • 是不是感觉世界瞬间安静了,只需要2行代码,解决了Android 4.4极其繁琐的代码,毕竟科技在进步。但你认为这就完了么?并不是,我给大家带来的是对状态栏完整的开发流程,Android 6.0还有新的API等着我们去实现呢!

浅色状态栏的开发

  • 浅色状态栏的开发需要API LEVEL >= 23,或MIUI或Flyme,这两个系统只需要API LEVEL >= 19
  • 什么是浅色状态栏呢?当然就是状态栏的颜色很浅呀,这会造成什么问题呢?在Android 6.0以前,原生Android系统的状态栏字体是强制为白色的,并且不能修改,所以当你的状态栏颜色很浅的时候,状态栏的字体几乎不可见的。
    如图

是不是状态栏看起来有一种瞎眼的感觉呢?所以谷歌在Android 6.0引入了浅色状态栏模式,进入这个模式以后,状态栏字体会自动变为黑色,以适应浅色状态栏。
注意:MIUI与Flyme重写了调整字体颜色的方法,所以使用谷歌官方的API是不起作用的,请注意!
对于MIUI,Flyme的浅色状态栏开发,大家可以参考这篇文章,这里不赘述实现方法
Android浅色状态栏黑色字体模式(截止2017年7月13日,Flyme和MIUI已经全部对自己的API进行了修改,这篇文章的代码已经不能在最新的两家系统上生效了,但是你可以参考学习一下)
下面讲一下官方的实现方式

Activity:

    public void setLightMode(Activity activity, boolean isLightMode) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){                //切换到浅色状态栏模式,黑字                activity.getWindow().getDecorView()                .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);            }else {                //切换到深色模式,白字                activity.getWindow().getDecorView()                .setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);            }        }    }

使用后的效果

  • 好了,基本上所有设计到状态栏的开发到现在告一段落了,随后的就是我自己开发的框架了,继承了上述所有的功能,一键实现,是不是很期待呢?

LightImmersionMode框架的使用

  • 千呼万唤终于写到这里,我的手都快断了,233。现在就让大家体会一下这个框架的方便之处吧。
  • 框架的GitHub地址:https://github.com/liyuhaolol/LightImmersionMode
  • GItHub上已经有非常详细的使用方法了,不妨看一下,这里当然也会写。

演示效果

  • 框架支持activity和fragment,支持随时在项目中改变状态栏。

引用方法

  • 在gradle中:
    compile 'spa.lyh.cn:immersion-sdk:1.0.5'
  • 在maven中:
<dependency>    <groupId>spa.lyh.cn</groupId>    <artifactId>immersion-sdk</artifactId>    <version>1.0.5</version>    <type>pom</type></dependency>

主要的类介绍

  • ImmersionMode : 沉浸式状态栏的主体类
  • ImmersionConfiguration : 沉浸式状态栏的配置类

使用方式

  • 本框架沉浸式效果仅支持API LEVEL >= 19以上的系统才可以生效对应效果
  • 本框架浅色状态栏,自适应字体仅支持MIUI或者Flyme系统,或者API LEVEL >= 23的其他系统才会有对应效果
  • 本框架支持最低API LEVEL >= 11但是API LEVEL < 19,会造成本框架不运行,不会造成程序崩溃

简单实现2个步骤:

1、先完成ImmersionModeImmersionConfiguration的初始化配置

//初始化对应的配置ImmersionConfiguration configuration = new ImmersionConfiguration        .Builder(this)        .enableImmersionMode(ImmersionConfiguration.ENABLE)        .setColor(R.color.bar_color)        .build();//完成ImmersionMode的配置初始化ImmersionMode.getInstance().init(configuration);

2、在activity的onCreate()生命周期中完成单例,并需要重写setContentView()方法,在其中完成方法调用

    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        immersionMode = ImmersionMode.getInstance();    }    @Override    public void setContentView(@LayoutRes int layoutResID) {        super.setContentView(layoutResID);        immersionMode.execImmersionMode(this);    }

需要临时修改相应属性:
修改临时配置的方法,一次性的设置不会影响默认的配置,再次加载会重新加载默认设置

    //使用资源的colorID赋值    public void changeStatusBarColor(int ResId){        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){            ImmersionConfiguration tConfig = new ImmersionConfiguration.Builder(this)                    .setColor(ResId)                    .build();            immersionMode.setTemporaryConfig(tConfig);            immersionMode.execImmersionMode(this);        }    }    //使用String的Color    public void changeStatusBarColor(String color){        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){            ImmersionConfiguration tConfig = new ImmersionConfiguration.Builder(this)                    .setColor(color)                    .build();            immersionMode.setTemporaryConfig(tConfig);            immersionMode.execImmersionMode(this);        }    }

Config的所有属性介绍

//启动public static int ENABLE = 100;//不启动public static int DISABLE = 101;
  • ImmersionConfiguration的属性设置方法

    enableImmersionMode():是否启动沉浸式状态栏,默认为:ENABLE

    setColor():传入资源id或者String型Color,默认为:#D0D0D0

注意事项

  • 因为API LEVEL >= 19 && API LEVEL < 21时,使用的沉浸式开发,方法immersionMode.execImmersionMode(this);会在setContentView()完成以后立刻调用,又因为沉浸式开发,是不可逆的设置,意思就是如果开启沉浸式,除非重新加载Activity否则无法翻转此状态。所以想要关闭本框架,那么对应方法必须在setContentView()之前调用,否则在Android4.4上会出现框架依然启动的BUG。
  • 最低API LEVEL >= 21时,可以无视上述问题,因为Android5.0以上并没有使用沉浸式开发,所以使用本框架可以不许重写setContentView()等种种限制运行顺序和生命周期的方式,只要在onResume()之前任意位置调用即可。

后记

  • 整整写了一天,终于完成了,我写这篇博客的动力,还是在于,现在晚上的对于沉浸式状态栏的开发文章十分零碎,新手看从sdk 19到sdk 21到sdk 23还有miui,flyme,真的看起来很晕,我自己踩坑,填坑,把这方面来一个大集合的文章,可以让大家得到一个完整阅读体验。当然我自己也得到很多,谢谢大家观看了,给好评,分享好不,么么哒!

联系方式

  • Github: https://github.com/liyuhaolol
  • 博客: http://blog.csdn.net/ccffvii
  • 邮箱: liyuhaoid@sina.com

有任何意见和问题,欢迎在评论中提出,一定尽快回复。


4 1