我在使用沉浸式的时候遇到很多坑,最典型的就是兼容性问题,有的效果5.0以上很容易实现,但在4.4使用同样的方法就不可取了,有的机型底部有虚拟导航按钮,有的却没有,所有我们不仅要区分手机的版本,也要区分底部是否有导航栏。只有在4.4及以上才有沉浸式这么一说的,在本次封装中,我们要同时实现顶部状态栏和底部导航栏的沉浸式,需要的童鞋可以当做工具类,直接copy到自己的BaseActivity中进行使用。
之前写过实现沉浸式方法的文章,详情见http://blog.csdn.net/sinat_35159441/article/details/76839484 ,首先我们来分析一下,不是所有的Activity都需要实现沉浸式,所以设置沉浸式的方法没必要做成抽象的,需要使用的Activity重写一下即可。该方法实现步骤如下:
- 如果当前版本为4.4,我们首先设置状态栏和导航栏透明,5.0不用
//判断手机的版本,如果是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);
}
在布局里加入
* 判断版本,4.4以下可以忽略,4.4使用反射机制动态设置Toolbar的高度,再设置其颜色,同样使用反射设置导航栏的高度,再设置其颜色,5.0以上直接使用官方提供的API设置其颜色,高度使用默认的。
/**
* 设置顶部及底部的沉浸式,这个方法需要子类来调,必须在setContentView()之后调用
*/
public void setTranslucentBar(final Toolbar toolbar, final View navigationView, int barColor) {
//当手机的版本在4.4的时候,设置透明之后,再设置高度,然后再设置显示的颜色
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT &&
Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
if (toolbar != null) {
toolbar.post(new Runnable() {
@Override
public void run() {
ViewGroup.LayoutParams layoutParams = toolbar.getLayoutParams();
layoutParams.height += getBarHeight("status_bar_height");
toolbar.setLayoutParams(layoutParams);
}
});
toolbar.setBackgroundColor(barColor);
}
if (navigationView != null) {
//这时还要判断当前手机有没有底部虚拟导航栏,如果没有的话,我们不做处理
if (hasNavigationView(getWindowManager())) {
navigationView.post(new Runnable() {
@Override
public void run() {
ViewGroup.LayoutParams layoutParams = navigationView.getLayoutParams();
layoutParams.height += getBarHeight("navigation_bar_height");
navigationView.setLayoutParams(layoutParams);
}
});
navigationView.setBackgroundColor(barColor);
}
}
//5.0及以上
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(barColor);
getWindow().setNavigationBarColor(barColor);
toolbar.setBackgroundColor(barColor);
} else {
//4.4以下,没有沉浸式这一说,我们不做任何处理
}
}
最终我的基类的代码如下:
/**
* 实现顶部及底部沉浸式导航栏的基类
*/
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(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);
}
}
/**
* 设置顶部及底部的沉浸式,这个方法需要子类来调,必须在setContentView()之后调用
*/
public void setTranslucentBar(final Toolbar toolbar, final View navigationView, int barColor) {
//当手机的版本在4.4的时候,设置透明之后,再设置高度,然后再设置显示的颜色
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT &&
Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
if (toolbar != null) {
toolbar.post(new Runnable() {
@Override
public void run() {
ViewGroup.LayoutParams layoutParams = toolbar.getLayoutParams();
layoutParams.height += getBarHeight("status_bar_height");
toolbar.setLayoutParams(layoutParams);
}
});
toolbar.setBackgroundColor(barColor);
}
if (navigationView != null) {
//这时还要判断当前手机有没有底部虚拟导航栏,如果没有的话,我们不做处理
if (hasNavigationView(getWindowManager())) {
navigationView.post(new Runnable() {
@Override
public void run() {
ViewGroup.LayoutParams layoutParams = navigationView.getLayoutParams();
layoutParams.height += getBarHeight("navigation_bar_height");
navigationView.setLayoutParams(layoutParams);
}
});
navigationView.setBackgroundColor(barColor);
}
}
//5.0及以上
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(barColor);
getWindow().setNavigationBarColor(barColor);
toolbar.setBackgroundColor(barColor);
} else {
//4.4以下,没有沉浸式这一说,我们不做任何处理
}
}
/**
* 判断当前手机是否含有底部导航栏,如果没有的话返回false,有的话返回true
*
* @return
*/
private boolean hasNavigationView(WindowManager wm) {
Display display = wm.getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics();
display.getRealMetrics(outMetrics);
//获取屏幕实际的高度,实际的高度包括内容的高度和底部导航的高度
int realHeight = outMetrics.heightPixels;
outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);
//屏幕中内容的高度
int heightPixels = outMetrics.heightPixels;
//如果实际的高度和大于内容的高度说明该手机含有底部导航,否则没有
return realHeight - heightPixels > 0;
}
/**
* 获取状态栏或是底部导航栏的高度
*
* @return
*/
public int getBarHeight(String dimenName) {
int height = 0;
try {
Class clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
String s = clazz.getField(dimenName).get(object).toString();
int heightId = Integer.parseInt(s);
//dp 2 px
height = getResources().getDimensionPixelSize(heightId);
} catch (Exception e) {
e.printStackTrace();
}
return height;
}
}
它的子类的代码如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
navigationView = findViewById(R.id.navi);
setTranslucentBar(toolbar, navigationView, getResources().getColor(R.color.barcolor));
}
最终效果如下: