、
- FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
挤占了状态栏的高度的时候,我们的布局文件也跟着顶到了状态栏上。通过
- FLAG_TRANSLUCENT_STATUS
,系统会把 app 布局文件的
- FitsSystemWindows
修改成状态栏的高度,达到适配的效果
- paddingTop
类型,通过
- ContentFrameLayout
可以获取到我们布局 xml 的根节点
- ((ViewGroup)findViewById(R.id.content)).getChildAt(0);
,就是基于这个
- findViewById()
查找里面的子节点的。比如 Activity 主题是
- DecorView
的组织层级如下,
- Theme.AppCompat.Light.NoActionBar
这种情况一般用于把图片延伸到状态栏上,图片还分两种
的全屏大图
- background
控件存在,一般只占屏幕高度的一部分
- ImageView
这两种情况下的处理方式还不一样,具体看下文
- /** * 使状态栏透明 */
- private static void transparentStatusBar(Activity activity) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
- activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
- }
- else {
- activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
- }
- }
上面的代码针对 5.0 以上或者 4.4 以上 5.0 以下的机型,让其状态栏透明、导航栏半透明,效果如下:
dump 了下节点信息,我们发现布局的 paddingTop 从(50px 状态栏高度)被修改成了 0px。从而让图片延伸到了状态栏
这种情况下,对 app 布局文件通过设置
就可以完成适配了
- FitsSystemWindows
- /**
- * 获取activity的根节点
- activity
- */
- public static ViewGroup getAppRootView(Activity activity) {
- return (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
- }
- /**
- *将目标View的paddingTop从0设置为状态栏的高度
- */
- private static void setRootViewFitSystemWindow(Activity activity) {
- ViewGroup rootView = getAppRootView(activity);
- rootView.setFitsSystemWindows(true);
- rootView.setClipToPadding(true);
- }
注意!!要延伸到状态栏的图片,如果不是根节点的背景图,而是一个 ImageView 控件,那么就不能设置
了,原因参考上图红框。这种情况下,为了防止顶到状态栏,需要手动在 xml 里通过
- setFitsSystemWindows
、
- paddingTop
调整标题栏元素位置达到适配。类似下图
- marginTop
设置状态栏颜色的步骤和透明类似,差别在于 5.0 以下机型无法直接设置状态栏颜色,我们可以模拟一个纯色的 View 放到状态栏下面间接达到着色效果。放置的父层级我们选择
- DecorView
- /**
- *
- 设置状态栏颜色
- *
- * @param activity 需要设置的activity
- * @param color 状态栏颜色值
- * @param statusBarAlpha 状态栏透明度
- */
- public static void setColor(Activity activity, int color, int statusBarAlpha) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- activity.getWindow().setStatusBarColor(UIUtils.calcColorWithAlpha(color, statusBarAlpha));
- } else {
- activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
- insertMockStatusBackgroundView(decorView, color, statusBarAlpha);
- }
- setRootViewFitSystemWindow(activity);
- }
所以我们要做的有 2 步
;以覆盖到状态栏上
- fitSystemWindow=false
代码如下:
- /** * 为DrawerLayout 布局设置状态栏变色
- *
- * @param activity 需要设置的activity
- * @param drawerLayout DrawerLayout
- * @param color 状态栏颜色值
- * @param statusBarAlpha 状态栏透明度
- */
- public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, int color, int statusBarAlpha) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
- return;
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
- } else {
- activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- }
- ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
- //如果内容view不是LinearLayout,则需要重新排列内容view子元素的内容
- insertMockStatusBackgroundView(contentLayout, color, statusBarAlpha);
- drawerLayout.setFitsSystemWindows(false);
- }
上面三个方法,涵盖了 app 在大部分沉浸场景下的状态。在了解了底层实现后,我们也可以轻松在安卓上实现 IOS 的沉浸效果了,最低版本 4.4 kitkat 现在已经非常普及,随着 MIUI、FlyME 相继都升级到 5.0、6.0 以上,魅蓝、红米等大批国产中低端机型的都可以体验到这种酷炫的效果了。
来源: http://www.bubuko.com/infodetail-2011226.html