Android沉浸式状态栏攻略

前言

这里不讨论[沉浸式]这个词用得好不好, 大家听得懂就行. 这篇文章主要是我在实际项目中的一些经验, 整理出来和大家分享, 欢迎探讨. 由于实习一直是996, 没时间做总结, 今天突然觉得这样的工作让我都忘了生活了, 是时候做个了断了. 写这篇文章的时候已经是23:44, 来不及贴一些demo, 但是这里的代码都是曾经的项目中摘出来的, 是可以运行的, 但我现在没有真的执行一遍. 注意所有的代码都只在android 4.4及以上有效.

考虑

根据实际项目的不同, 可能选择的沉浸式实现策略也会有所不同.

传统纯色actionbar

如果你的app使用的是遵循android规范的actionbar或者有一个纯色layout放在屏幕顶部, 那么这里有一个入侵较小的方案, 这个方案的实现方式是参考的开源项目SystemBarTint. 让你的activity继承一个BaseActivity, 在BaseActivity里面重写onPostCreate

(Bundle savedInstanceState) {super.onPostCreate(savedInstanceState);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {ImmerseHelper.setSystemBarTransparent(this);}}

重点在ImmerseHelper这个类里, 先贴代码再讲解.

{@TargetApi(Build.VERSION_CODES.KITKAT)(Activity paramActivity){Window window = paramActivity.getWindow();WindowManager.LayoutParams layoutParams = window.getAttributes();layoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;window.setAttributes(layoutParams);hackStatusBarTransparent(paramActivity);setContentPadding(paramActivity);}(Activity paramActivity) {ViewGroup localViewGroup = (ViewGroup) paramActivity.getWindow().getDecorView().findViewById(android.R.id.content);View colorview = new View(paramActivity);colorview.setBackgroundResource(R.color.statusbar_color);localViewGroup.addView(colorview, ViewGroup.LayoutParams.MATCH_PARENT,ImmerseHelper.getStatusBarHeight(paramActivity));}(Activity activity) {((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0).setPadding(0, ImmerseHelper.getStatusBarHeight(activity)+ ImmerseHelper.getActionBarHeight(activity), 0, 0);}/*** 获取状态栏高度, 单位px* @param context* @return*/(Context context) {int result = 0;int resourceId = context.getResources().getIdentifier(“status_bar_height”, “dimen”, “android”);if (resourceId > 0) {result = context.getResources().getDimensionPixelSize(resourceId);}return result;}/*** 获取actionbar高度, 单位px* @param context* @return*/(Context context){TypedValue localTypedValue = new TypedValue();if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, localTypedValue, true)) {return TypedValue.complexToDimensionPixelSize(localTypedValue.data, context.getResources().getDisplayMetrics());}return 0;}}

简单来说就是在postCreate时对activity做手脚, 这样组内其他开发者几乎感受不到变化, 只需要将activity的基类指定成BaseActivity就好 ImmerseHelper这个类主要做了三件事 – 将window的FLAG_TRANSLUCENT_STATUS标志打开 – 给某个View中添加了一个与状态栏大小完全相同的纯色块 – 给activity的根View设置paddingTop FLAG_TRANSLUCENT_STATUS这个标志打开之后, 状态栏就透明了, 同时我们的activity的主体布局, 也就是setContentView传入的那个布局, 会顶到屏幕最上方, 被状态栏盖住一部分, 注意actionbar是不会受影响的. 所以我们在第三步给activity的根view设了paddingTop, 高度是状态栏的高度加上actionbar的高度, 这样activity中的内容才会回到之前的正常位置. 但此时状态栏下方透明了, 所以我们给某个View中添加了一个与状态栏大小完全相同的色块, 颜色和actionbar一致, 这样就有了沉浸式效果. 当然这里的效果是状态栏下面有一层半透明黑底, 之后才是我们添加的view, 所以不用担心看不到状态文字, 在4.4上只能做到这个效果, 5.0上可以让状态栏底部完全透明, 这个等会儿说. 不过光有实现不行, 还需要知道为什么我们要这么做

原理

先看一下hierarchy view的截图

我们getDecorView拿到的是最左边的DecorView, 而setContentView影响的是id/content那个view的直接子view, 和id/content平级的view是actionbar. activity.getWindow().getDecorView().findViewById(android.R.id.content);这句拿到的是id/content这个view, 我们向其中添加一个纯色view, 由于打开了FLAG_TRANSLUCENT_STATUS, 这个纯色view就直接顶在最上面, 也就是状态栏覆盖的地方. SystemBarTint中并非是向id/content中addView, 而是直接向getDecorView()中addView, 而SwipeBackLayout则是在DecorView和他的子View之间插入自己的layout, 相当于劫持了DecorView的子View, 所以如果同时使用这两个开源项目不加修改, 要么滑动返回划走的是状态栏, 要么状态栏撕裂. 如果像我这么写, 就不会和SwipeBackLayout冲突.

非传统

如果你要做到向上图这样, 图片完全顶在顶部, 那么就不建议使用actionbar了, 同时也不需要setContentPadding这步. 有时这样会导致某些页面的内容过分偏上, 这个时候建议用一个dimen, 在正常情况下是0dp, v19及以上时是24dp, 这也是状态栏高度, 哪些页面要隔开状态栏, 就用这个dimen做marginTop, 或者include一个高度为这个dimen的layout. 这样子的入侵比较强, 做新的页面需要时刻注意和状态栏是否需要保持距离, 很容易忘记, 不过也不算什么困难, 毕竟一运行就看出来了.

Lolipop+特有方法我走得很慢!但我从不后退!

Android沉浸式状态栏攻略

相关文章:

你感兴趣的文章:

标签云: