什么是沉浸式?
沉浸式这个概念提出来很久了,相信大家也都知道是什么。是什么我不啰嗦了,反正玩来玩去就是在玩状态栏的颜色。
我记得 MaterialDesign 系列的第一篇文章就给大家分享了一张图。
对,没错,我们今天要讲的就是图上的StatusBarColor。沉浸式也就是在玩这个 StatuBarColor,其实没什么意思。
如 全民TV 的首页设计
怎么用
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 都设置这个属性,多麻烦,哈哈哈~
第二个问题:可能很多同学都会有这样的场景需求,我们需要一个全透明的状态栏覆盖在图片上方,如下图
但是实际上却变成了这样,半透明
妈卖批,这是为什么,我明明设置了 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~