沉浸式设计基本概念
官方的沉浸式Translucent定义:就是让整个APP沉浸(充斥了整个屏幕)在屏幕里面,没有显示状态栏,甚至没有显示底部导航栏。
平时大家所讨论的沉浸式:比如QQ的顶部Toolbar和状态栏程一体的颜色。
5.0以上状态栏沉浸式设计
5.0+自动实现了沉浸式效果,状态栏的颜色跟随你的主题里面的colorPrimaryDark属性。
例如我们直接在主题里面设置colorPrimaryDark即可,也可以设置colorPrimaryDark:
由于每一个Activity(Fragment)的沉浸式颜色可能不一样,因此我们可以通过代码去设置:
//5.0+可以直接用API来修改状态栏的颜色。
getWindow().setStatusBarColor(getResources().getColor(R.color.material_blue_grey_800));
(注意:要在setContentView方法之前设置)
4.4以上状态栏沉浸式设计
用到一些特殊手段!----4.4(KitKat)新出的API,可以设置状态栏为透明的。
注意:低于4.4API,不可以做到
下面介绍一些方法:
一、通过设置属性样式(不推荐,兼容性不好)
在主题里面添加(注意需要在v-19以上的资源文件中添加哦):
- true
二、2.在代码里面解决(笔者认为通过这个方法,已经可以解决4.4以上的所有问题了,因此特别推荐)
在Activity里面添加
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
setContentView(R.layout.activity_main);
但是,APP的内容顶到最上面去了,即状态栏会遮挡一部分界面。
解决办法(有几种):
- 给布局最外层容器设置android:fitsSystemWindows="true" 。
- 给Toolbar设置top padding,但是这时候我们需要通过反射去获取状态栏的高度:
修改Toolbar的PaddingTop(因为纯粹增加toolbar的高度会遮挡toobar里面的一些内容)
/**
* 获取状态栏的高度
* @param context
* @return
*/
private int getStatusBarHeight(Context context) {
// 反射手机运行的类: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("status_bar_height").get(object).toString();
int height = Integer.parseInt(heightStr);
//dp--->px
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusHeight;
}
然后给Toolbar设置padding:
toolbar.setPadding(
toolbar.getPaddingLeft(),
toolbar.getPaddingTop()+getStatusBarHeight(this),
toolbar.getPaddingRight(),
toolbar.getPaddingBottom());
注意:当你的toolbar是白色的时候,如果手机系统的状态栏的文字又刚好是白色的话,我们可以不用padding,而是使用一个渐变的半透明黑色.9图,类似360手机助手的效果
关于状态栏的沉浸式,还可以使用第三方的沉浸式解决方案:SystemTint,但是也会有一些坑。
5.0以上底部导航栏沉浸式设计
底部的虚拟按键导航栏我们一般很少去适配,这里只给出一些简单的解决方案。
5.0+ 可以用主题样式解决:
- @color/system_bottom_nav_color
或者代码实现:
getWindow().setNavigationBarColor()
4.4以上底部导航栏沉浸式设计
用到一些特殊手段!----4.4(KitKat)新出的API,可以设置虚拟导航栏为透明的。
步骤:
- 在布局底部添加一个高度为0.1dp的view
- 动态设置底部View的高度为虚拟导航栏的高度
代码:
/**
* 获取底部虚拟按键的高度
* @param context
* @return
*/
private int getStatusBarHeight(Context context) {
// 反射手机运行的类:android.R.dimen.navigation_bar_height.
int statusHeight = -1;
try {
Class> clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
String heightStr = clazz.getField("navigation_bar_height").get(object).toString();
int height = Integer.parseInt(heightStr);
//dp--->px
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusHeight;
}
然后在代码中设置:
View nav = findViewById(R.id.nav);
LayoutParams p = nav.getLayoutParams();
p.height += getNavigationBarHeight(this);
nav.setLayoutParams(p);
另外,还需要做兼容性判断:
1)SDK版本不一样,按照上述方法做不同处理:
两个区间:1. 大于5.0;2.=<4.4sdk<5.0
2)有的没有虚拟导航栏
判断是否有虚拟导航栏(源码里面有方法可以得到是否有虚拟导航,反射得到)
3)有的有虚拟导航,但是还可以开关
判断是否虚拟导航栏打开了
最后,我们封装一个具有上述功能的BaseActivity
@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.KITKAT
&&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;
System.out.println("~~~~~~~~~~~~~~~~h:"+h);
return w>0||h>0;//竖屏和横屏两种情况。
}
}
如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:
我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)。