Android中的沉浸式设计
在Android官方的Material Design指导中,有一种界面的设计方案是沉浸式设计。所谓的沉浸式设计,就是只App的界面完全和屏幕和系统融合。而不是带有系统组件的特点。例如:标题栏一般都是有系统的颜色的,比如黑色状态栏 浅灰色状态栏 。导航栏也有系统的颜色。沉浸式就是通过修改一些组件的风格和效果。使得和当前运行的App一致,达到整个界面都是相同的设计元素。
沉浸式个人认为来说是一个设计的思想。但是对于实现的方案有不同的实现。各个大厂也都有自己的实现方案。这里我总结个人的沉浸式的实现方式。也是目前用在项目中的沉浸式设计方案
由于Android 有很多版本 各个版本的效果差异比较明显,所以在我们实现沉浸式的时候。要考虑兼容问题。针对不同版本有不同的实现方案。
官方的沉浸式Translucent:就是让整个App沉浸在屏幕里面,有点类似全屏的效果。
标题栏沉浸式设计
针对5.0以上的API
1 我们可以通过设置主题
2 可以通过设置样式属性来解决。可以设置style.xml
- @color/system_bottom_nav_color
3 通过代码设置
getWindow().setStatusBarColor(getResources().getColor(R.color.material_blue_grey_800));
(注意:要在setContentView方法之前设置)
针对4,4API
由于在4.4中新增了API,可以设置状态栏为透明的
1 可以在属性样式里面解决(这种方式不推荐,会出现兼容性的问题)
- true
2 可以在代码里解决
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
setContentView(R.layout.activity_main);
在这种情况下,会出现APP的内容被顶到了上面,状态栏会遮挡界面
解决方式如下:
1 给ToolBar设置android:fitsSystemWindows=true
这个属性的作用是:在设置布局时,是否考虑当前系统窗口的布局,如果设置为true就会调整整个系统窗口布局包括状态栏的view以适应你的布局。
但是这种情况下,当里面有ScrollView并且里面有Edittext的时候,就会出现软键盘弹起后会把toolbar拉取下来的bug
2 这里我们推荐的做法是,在布局最外层容器设置android:fitsSystemWindows=true,可以达到状态栏不会被输入法影响产生Bug
步骤:
* 1.在最外层容器设置android:fitsSystemWindows="true"
* 2.不要给Toolbar设置android:fitsSystemWindows="true"
* 2.直接将最外层容器(也可以修改-android:windowBackground颜色)设置成状态栏想要的颜色
* 3.下面剩下的布局再包裹一层正常的背景颜色。
3 修改ToolBar的高度
1.不要给Toolbar设置android:fitsSystemWindows="true"
2.需要知道状态栏的高度是多少?去源码里面找找
24dp
48dp
反射手机运行的类:android.R.dimen.status_bar_height.
3.修改Toolbar的PaddingTop(因为纯粹增加toolbar的高度会遮挡toobar里面的一些内容)
toolbar.setPadding(
toolbar.getPaddingLeft(),
toolbar.getPaddingTop()+getStatusBarHeight(this),
toolbar.getPaddingRight(),
toolbar.getPaddingBottom());
4.或者可以设置toolbar的高度(不推荐)
底部虚拟导航栏设计
5.x 调用提供的API实现
1 属性解决
navigationBarColor
2 代码
getWindow().setNavigationBarColor()
4.4版本 用一些特殊手段。设置底部虚拟导航栏为透明
步骤:
1)在布局底部添加一个高度为0.1dp的view
2)动态设置底部View的高度为虚拟导航栏的高度
View nav = findViewById(R.id.nav);
LayoutParams p = nav.getLayoutParams();
p.height += getNavigationBarHeight(this);
nav.setLayoutParams(p);
具体案例
我们需要创建一个BaseTranslucentActivity作为父Activity
/**
* @author wxblack-mac
* @DESCRIBE:沉浸式状态栏的父Activity
* @DATE 2019/3/6 10:33
* GOOD LUCK
*/
@SuppressLint("Registered")
public class BaseTranslucentActivity extends AppCompatActivity {
private Toolbar toolbar;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//判断系统版本
//[4.4,5.0) 手动实现沉浸式状态栏和导航栏透明
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
//状态栏透明
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//导航栏透明
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
public void setOrChangeTranslucentColor(Toolbar toolbar, View bottomNavigationBar, int translucentPrimaryColor) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
if (toolbar != null) {
//1.先设置toolbar的高度
ViewGroup.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);
}
if (bottomNavigationBar != null) {
//解决低版本4.4+的虚拟导航栏的
if (hasNavigationBarShow(getWindowManager())) {
ViewGroup.LayoutParams p = bottomNavigationBar.getLayoutParams();
p.height += getNavigationBarHeight(this);
bottomNavigationBar.setLayoutParams(p);
//设置底部导航栏的颜色
bottomNavigationBar.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;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
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;//竖屏和横屏两种情况。
}
}
在子Activity调用的时候 MainActivity
public class MainActivity extends BaseTranslucentActivity {
private Toolbar toolbar;
private View navigationView;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = ((Toolbar) findViewById(R.id.toolbar));
navigationView = findViewById(R.id.nav);
setOrChangeTranslucentColor(toolbar, navigationView, getResources().getColor(R.color.colorPrimary));
}
}