Android UI进阶之旅9 Material Design之沉浸式设计

###沉浸式设计基本概念

官方的沉浸式Translucent定义:就是让整个APP沉浸(充斥了整个屏幕)在屏幕里面,没有显示状态栏,甚至没有显示底部导航栏。

平时大家所讨论的沉浸式:比如QQ的顶部Toolbar和状态栏程一体的颜色。

###5.0以上状态栏沉浸式设计

5.0+自动实现了沉浸式效果,状态栏的颜色跟随你的主题里面的colorPrimaryDark属性。

例如我们直接在主题里面设置colorPrimaryDark即可,也可以设置colorPrimaryDark:

<style name="AppTheme" parent="AppBaseTheme">
	<item name="colorPrimaryDark">@color/colorPrimary_pinkDark</item>
	<item name="android:statusBarColor">@color/colorPrimary_pinkDark</item>
</style>
复制代码

由于每一个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以上的资源文件中添加哦):

<item name="android:windowTranslucentStatus">true</item>
复制代码

####二、2.在代码里面解决(笔者认为通过这个方法,已经可以解决4.4以上的所有问题了,因此特别推荐)

在Activity里面添加

getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
setContentView(R.layout.activity_main);
复制代码

但是,APP的内容顶到最上面去了,即状态栏会遮挡一部分界面。

解决办法(有几种):

  1. 给布局最外层容器设置android:fitsSystemWindows="true" 。
  2. 给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+ 可以用主题样式解决:

<item name="android:navigationBarColor">@color/system_bottom_nav_color</item>
复制代码

或者代码实现:

getWindow().setNavigationBarColor()
复制代码

###4.4以上底部导航栏沉浸式设计

用到一些特殊手段!----4.4(KitKat)新出的API,可以设置虚拟导航栏为透明的。

步骤:

  1. 在布局底部添加一个高度为0.1dp的view
  2. 动态设置底部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.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");
	}

	/**
	 * 获取状态栏的高度
	 * @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,我拉你进群交(♂)流(♀)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值