MaterialDesign--(8)沉浸式设计

什么是沉浸式?

沉浸式这个概念提出来很久了,相信大家也都知道是什么。是什么我不啰嗦了,反正玩来玩去就是在玩状态栏的颜色。

我记得 MaterialDesign 系列的第一篇文章就给大家分享了一张图。

对,没错,我们今天要讲的就是图上的StatusBarColor。沉浸式也就是在玩这个 StatuBarColor,其实没什么意思。
如 全民TV 的首页设计

WechatIMG10.png

怎么用

getWindow().setStatusBarColor(int color);
好了,讲完了。

兼容性问题

刚刚这个方法仅适用与5.0+的手机,如果要兼容5.0以下的手机,则状态栏只支持透明效果,但是没有 api 提供去设置颜色。
4.4以前的手机不支持修改状态栏颜色
现在我们就来看看怎么修改4.4~5.0的状态栏颜色。
首先我们的,系统中有一个 windowTranslucentStatus 属性,不知道大家用过没,就是设置状态栏为半透明,并且会被 View 填充。然后我们的思路就是,抽取出 TranslucentActivity,然后提供方法,让 Toolbar 填充状态栏。
第一步,在 values-v19/style.xml 文件里面给 style 添加下面这条属性

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

第二步,使用继承了这个 Theme 的 的主题给 Activity。
第三步,抽取 BaseTranslucentActivity

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public class BaseTranslucentActivity extends AppCompatActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //判断版本,如果[4.4,5.0)就设置状态栏和导航栏为透明
    if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.KITKAT
            &&android.os.Build.VERSION.SDK_INT<android.os.Build.VERSION_CODES.LOLLIPOP){
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        //设置虚拟导航栏为透明
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
    }
}

@SuppressLint("NewApi")
public void setOrChangeTranslucentColor(Toolbar toolbar,int translucentPrimaryColor){
    //判断版本,如果[4.4,5.0)就设置状态栏和导航栏为透明
    if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.KITKAT
            &&android.os.Build.VERSION.SDK_INT<android.os.Build.VERSION_CODES.LOLLIPOP){
        if(toolbar!=null){
            //1.先设置toolbar的高度
            LayoutParams params = toolbar.getLayoutParams();
            int statusBarHeight = getStatusBarHeight(this);
            params.height += statusBarHeight ;
            toolbar.setLayoutParams(params );
            //2.设置paddingTop,以达到状态栏不遮挡toolbar的内容。
            toolbar.setPadding(
                    toolbar.getPaddingLeft(),
                    toolbar.getPaddingTop()+getStatusBarHeight(this),
                    toolbar.getPaddingRight(),
                    toolbar.getPaddingBottom());
            //设置顶部的颜色
            toolbar.setBackgroundColor(translucentPrimaryColor);
        }else if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.LOLLIPOP){
        getWindow().setNavigationBarColor(translucentPrimaryColor);
        getWindow().setStatusBarColor(translucentPrimaryColor);
    }else{
        //<4.4的,不做处理
    }
}


private int getNavigationBarHeight(Context context) {
    return getSystemComponentDimen(this, "navigation_bar_height");
}

/**
 * 获取状态栏的高度
 * @param context
 * @return
 */
private int getStatusBarHeight(Context context) {
    // 反射手机运行的类:android.R.dimen.status_bar_height.
    return getSystemComponentDimen(this, "status_bar_height");
}

private static int getSystemComponentDimen(Context context, String dimenName){
    // 反射手机运行的类:android.R.dimen.status_bar_height.
    int statusHeight = -1;
    try {
        Class<?> clazz = Class.forName("com.android.internal.R$dimen");
        Object object = clazz.newInstance();
        String heightStr = clazz.getField(dimenName).get(object).toString();
        int height = Integer.parseInt(heightStr);
        //dp--->px
        statusHeight = context.getResources().getDimensionPixelSize(height);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return statusHeight;
}

private static boolean hasNavigationBarShow(WindowManager wm){
    Display display = wm.getDefaultDisplay();
    DisplayMetrics outMetrics = new DisplayMetrics();
    //获取整个屏幕的高度
    display.getRealMetrics(outMetrics);
    int heightPixels = outMetrics.heightPixels;
    int widthPixels = outMetrics.widthPixels;
    //获取内容展示部分的高度
    outMetrics = new DisplayMetrics();
    display.getMetrics(outMetrics);
    int heightPixels2 = outMetrics.heightPixels;
    int widthPixels2 = outMetrics.widthPixels;
    int w = widthPixels-widthPixels2;
    int h = heightPixels-heightPixels2;
    return  w>0||h>0;//竖屏和横屏两种情况。
}
}

代码里面的注释清晰明了,简单粗暴。宝宝在做这一块兼容性开发的时候踩过很多很多的坑,查了很多资料,最后才有了这个类。使用反射机制获取代码中状态栏的高度,然后再给 Toolbar 设置 PaddingTop,然后就 Ok 了。
当然,你也可以用 fitsSystemWindows 为true 来,实现,那不那个需要给每个activity 的 xml 都设置这个属性,多麻烦,哈哈哈~

第二个问题:可能很多同学都会有这样的场景需求,我们需要一个全透明的状态栏覆盖在图片上方,如下图

WechatIMG8.jpeg

但是实际上却变成了这样,半透明

WechatIMG9.png

妈卖批,这是为什么,我明明设置了 windowTranslucentStatus 为 true,系统控件可以填充状态栏,然后再把状态栏设置为透明色啊。
后来,终于在一篇博客中找到了解决方案~~

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

不用设置 windowTranslucentStatus 为 true,直接使用这两个 flag 就好了,不会的同学赶紧做笔记~~

问题解决了,那么这些 flag 到底有什么作用呢,我们直接点击这个 flag 就可以看源码,源码里面都有英语注释的,下面是我统计好的一些 flag 的作用。

参数 api 版本 含义
View.SYSTEM_UI_FLAG_VISIBLE 14 默认标记
View.SYSTEM_UI_FLAG_LOW_PROFILE 14 低功耗模式, 会隐藏状态栏图标, 在4.0上可以实现全屏
View.SYSTEM_UI_FLAG_LAYOUT_STABLE 16 保持整个View稳定, 常跟bar 悬浮, 隐藏共用, 使View不会因为SystemUI的变化而做layout
View.SYSTEM_UI_FLAG_FULLSCREEN 16 状态栏隐藏
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 16 状态栏上浮于Activity
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 14 隐藏导航栏
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 16 导航栏上浮于Activity
View.SYSTEM_UI_FLAG_IMMERSIVE 19 Kitkat新加入的Flag, 沉浸模式, 可以隐藏掉status跟navigation bar, 并且在第一次会弹泡提醒, 它会覆盖掉之前两个隐藏bar的标记, 并且在bar出现的位置滑动可以呼出bar
View.SYSTEM_UI_FLAG_IMMERSIVE_STIKY 19 与上面唯一的区别是, 呼出隐藏的bar后会自动再隐藏掉

然后这里设置的 flag 会和WindowManger 的一些 flag相互影响,如果使用的过程中,出现了预测之外的效果,可以去看看源码注释,上面有说明哪些 flag 会影响到哪些 flag,或许能解决问题。

沉浸式牵涉到的知识点也就这些,有什么问题留言吧~

上周五有了新需求,所以这篇文章晚来了今天,Sorry~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 前言 首先请大家看几张图: 以上的效果,一般我们统称为沉浸式状态栏。其实,这种叫法不是很准确,而且也没有沉浸式状态...
    宇是我阅读 3,799评论 2 28
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,510评论 25 707
  • 一、前言 其实我是不打算写这篇文章的,为什么呢?因为关于沉浸式状态栏的文章太多了,随便google一下就能出来几十...
    依然范特稀西阅读 44,219评论 27 180
  • 何谓沉浸式状态栏## 说白了,沉浸式状态栏本质上就是给系统状态栏着色。当这个颜色和我们Activity中的Tool...
    chandarlee阅读 15,607评论 2 54
  • 职责分工控制 要求根据企业目标和职能任务,按照科学、精简、高效的原则,合理设置职能部门和工作岗位,明确各部门、各岗...
    ecollab阅读 1,157评论 0 1