高级UI之沉浸式设计

关于沉浸式设计,在国内指的是Toolbar和系统状态栏相统一,而谷歌官方给出的沉浸式则是指整个界面为UI所用,而这里所说的沉浸式则是指的前者,涉及4.4和5.0及以上,4.4以下的Android做不出沉浸式设计

头部沉浸式

在5.0及以上可以很简单的实现沉浸式,统一头部和和Toolbar的色彩,其主要是实现方式有三种

使用注意事项

要对系统版本做判断,分为三种情况,4.4以下,4.4,5.0及以上
在虚拟按键的有无判别上,需要得到是否有虚拟按键,虚拟按键是否打开
其实只需要的带虚拟按键的高度,而虚拟按键的高度等于整个屏幕的高度减去内容部分view的高度,判断其是否大于0即可

5.0及以上

设置主题实现

在主题里面指定了colorPrimaryDark则实现了头部的沉浸式

1
2
3
4
5
6
7
8
9
10
11
<resources>

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>

</resources>

设置样式属性实现

1
<item name="android:statusBarColor">@android:color/black</item>

在代码中设置实现

1
getWindow().setStatusBarColor(getResources().getColor(android.R.color.darker_gray));

4.4系统

在4.4系统做沉浸式稍显复杂,因为没有官方的支持,只能自己去实现

设置属性样式实现

但不推荐这样使用,这样存在兼容性问题

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

代码中和布局属性设置实现

首先设置状态栏为透明,然后在此基础之上完成沉浸式设计
这段代码应该位于setContentView()前面,设置以后才开始布局的绘制,不然会不起作用

1
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

此时状态栏变为透明,但Toolbar却往上移了,因此需要解决这个问题
Toolbar设置android:fitsSystemWindows="true"可以达到想要的效果,原因在于这个属性规定了设置布局时候是否考虑当前系统窗口的布局,但伴随而来的问题是这样使用的前提是没有ScrollView且其包含EditView,如果存在这种情况,会造成Toolbar的下拉,基于此产生了通用的解决方案
首先在最外层容器设置android:fitsSystemWindows="true",然后将最外层容器(也可以修改android:windowBackground颜色)设置成状态栏想要的颜色,最后将剩下的布局再包裹一层正常的背景颜色,这样就解决了4.4版本的沉浸式设计
当然,还有很多其他思路,比如修改Toolbar的高度,设置Toolbar的paddingTop等

或者直接使用第三方解决方案:SystemTint

虚拟按键沉浸式

5.0及以上

和头部设置一样,在5.0及以上版本中,由于系统支持,可以直接使用系统方法解决

属性设置

1
<item name="android:navigationBarColor">@android:color/darker_gray</item>

代码设置

1
getWindow().setNavigationBarColor(Color.GREEN);

4.4

设置虚拟按键为透明

1
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);

然后有两种设置方法:

  • 一种直接使用布局控制其高度
    使其虚拟按键高度小于等于设置的的View高度,这样也能实现底部沉浸式

  • 另一种方法就是布局加上代码的实现方式
    在布局底部添加一个高度为1dp的view
    动态设置底部View的高度为虚拟导航栏的高度

    1
    2
    3
    4
    View view = findViewById(R.id.view);
    LayoutParams params = view.getLayoutParams();
    params.height += getNavigationBarHeight(this);
    view.setLayoutParams(p);
1
2
3
4
5
6
7
8
9
10
11
12
13
private int getNavigationBarHeight(Context context) {
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);
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.prinStackTrace();
}
return statusHeight;
}

Demo综合判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
@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,View bottomNavigationBar, 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);
}
if(bottomNavigationBar!=null){
//解决低版本4.4+的虚拟导航栏的
if(hasNavigationBarShow(getWindowManager())){
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");
}

//获取状态栏的高度
private int getStatusBarHeight(Context context) {
return getSystemComponentDimen(this, "status_bar_height");
}

//反射手机运行的类:android.R.dimen
private static int getSystemComponentDimen(Context context, String dimenName){
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;//竖屏和横屏两种情况。
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MainActivity2 extends BaseTranslucentActivity{

private Toolbar toolbar;
private View navigation;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar)findViewById(R.id.toolbar);
navigation = findViewById(R.id.navigation);
setOrChangeTranslucentColor(toolbar, navigation, getResources().getColor(R.color.colorPrimary_pink));

}
}
Donate comment here