关于使用BGASwipeBackLayout-Android结合StatusBarUtil的问题

背景 【关于使用BGASwipeBackLayout-Android结合StatusBarUtil的问题】在写Reading的过程中,想实现仿IOS右滑关闭Activity的效果,在网上找到了BGASwipeBackLayout-Android
,看着效果不错,刚巧这个库也使用的猴子的StatusBarUtil
,在使用的过程中,效果确实不错,同时这个库也支持了右滑关闭Activity时候沉浸式通知栏,但是Reading里面用到了DrawerLayout,结合BGASwipeBackLayout-Android使用的时候出现了下面的问题,就是当从主Activity进入二层界面再返回的时候,底部Tab会弹一下再上来,效果有些炸眼....

关于使用BGASwipeBackLayout-Android结合StatusBarUtil的问题
文章图片
2018-08-25 00_05_55.gif
解决 想要解决这个问题无非从两个角度去思考

  • BGASwipeBackLayout-Android
  • StatusBarUtil
浩哥的BGA是通过修改support-v4 包中 SlidingPaneLayout 的源码来实现滑动返回布局,源码在BGASwipeBackLayout.java这里,大概过了一下,感觉还是挺复杂的。放弃了,然后通过查看浩哥支持的为滑动界面设置状态栏颜色的方法
/** * 为滑动返回界面设置状态栏颜色 * * @param activity 需要设置的activity * @param color状态栏颜色值 */ public static void setColorForSwipeBack(Activity activity, int color) { setColorForSwipeBack(activity, color, DEFAULT_STATUS_BAR_ALPHA); }

/** * 为滑动返回界面设置状态栏颜色 * * @param activity需要设置的activity * @param color状态栏颜色值 * @param statusBarAlpha 状态栏透明度 */ public static void setColorForSwipeBack(Activity activity, @ColorInt int color, @IntRange(from = 0, to = 255) int statusBarAlpha) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {ViewGroup contentView = ((ViewGroup) activity.findViewById(android.R.id.content)); View rootView = contentView.getChildAt(0); int statusBarHeight = getStatusBarHeight(activity); if (rootView != null && rootView instanceof CoordinatorLayout) { final CoordinatorLayout coordinatorLayout = (CoordinatorLayout) rootView; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { coordinatorLayout.setFitsSystemWindows(false); contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha)); boolean isNeedRequestLayout = contentView.getPaddingTop() < statusBarHeight; if (isNeedRequestLayout) { contentView.setPadding(0, statusBarHeight, 0, 0); coordinatorLayout.post(new Runnable() { @Override public void run() { coordinatorLayout.requestLayout(); } }); } } else { coordinatorLayout.setStatusBarBackgroundColor(calculateStatusColor(color, statusBarAlpha)); } } else { contentView.setPadding(0, statusBarHeight, 0, 0); contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha)); } setTransparentForWindow(activity); } }

这段代码我们可以看到通过获取根布局,如果跟布局是CoordinatorLayout的话,设置paddingTop,并且设置颜色重绘。否则给contentView设置了paddingTop并且设置颜色。参考这段代码,我们找到了猴子的为DrawerLayout提供的沉浸式代码
/** * 为DrawerLayout 布局设置状态栏变色 * * @param activity需要设置的activity * @param drawerLayoutDrawerLayout * @param color状态栏颜色值 * @param statusBarAlpha 状态栏透明度 */ public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color, @IntRange(from = 0, to = 255) 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); } // 生成一个状态栏大小的矩形 // 添加 statusBarView 到布局中 ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0); View fakeStatusBarView = contentLayout.findViewById(FAKE_STATUS_BAR_VIEW_ID); if (fakeStatusBarView != null) { if (fakeStatusBarView.getVisibility() == View.GONE) { fakeStatusBarView.setVisibility(View.VISIBLE); } fakeStatusBarView.setBackgroundColor(color); } else { contentLayout.addView(createStatusBarView(activity, color), 0); } // 内容布局不是 LinearLayout 时,设置padding top if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) { contentLayout.getChildAt(1) .setPadding(contentLayout.getPaddingLeft(), getStatusBarHeight(activity) + contentLayout.getPaddingTop(), contentLayout.getPaddingRight(), contentLayout.getPaddingBottom()); } // 设置属性 setDrawerLayoutProperty(drawerLayout, contentLayout); addTranslucentView(activity, statusBarAlpha); }

从代码来看,一眼看到代码注释//生成一个状态栏大小的矩形,也就是说支持DrawerLayout沉浸的原理是为跟布局设置 android:fitsSystemWindows="true",让整个屏幕都可以放组件,同时加了一个状态栏大小的矩形,并设置了颜色,这样就满足了DrawerLayout的沉浸式。
  • 1.fitsSystemWindow 默认是true,就是组件都在屏幕内,但是不包括statusBar。设置成false后,整个屏幕都可以放置组件,没有statusBar和window之分。
  • 2.android:fitsSystemWindows=“true”在布局中占有最高权限,如果明确设置为true,style设置fits为false是无效的;同理,只在布局中设置fits而没有设置style也是无效的。
好了,分析到这里我们不难想出来解决办法了,从浩哥提供的滑动关闭界面的沉浸代码中可以看到滑动关闭的Activity并没有设置android:fitsSystemWindows="true",那么这个Activity是有statusBar和window的区分的,通过设置了paddingTop来实现的,而猴子的setDrawerLayout支持的前提是为跟布局设置了android:fitsSystemWindows="true",也就是没有了statusBar,所以最终看到的效果就是上面的动态图,进入二级界面为了实现左滑界面的沉浸式,设置了浩哥的setColorForSwipeBack方法,当返回到主Activity时,由于主界面没有了statusBar,所以你会看到底部的tab会向上移动了一个statusBar的高度,最后解决的代码如下:
/** * 为滑动返回界面设置状态栏颜色 * * @param activity需要设置的activity * @param color状态栏颜色值 * @param statusBarAlpha 状态栏透明度 */ public static void setColorForSwipeBackDrawerLayout(Activity activity, @ColorInt int color, @IntRange(from = 0, to = 255) int statusBarAlpha) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {ViewGroup contentView = ((ViewGroup) activity.findViewById(android.R.id.content)); View rootView = contentView.getChildAt(0); int statusBarHeight = getStatusBarHeight(activity); if (rootView != null && rootView instanceof CoordinatorLayout) { final CoordinatorLayout coordinatorLayout = (CoordinatorLayout) rootView; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { coordinatorLayout.setFitsSystemWindows(false); contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha)); boolean isNeedRequestLayout = contentView.getPaddingTop() < statusBarHeight; if (isNeedRequestLayout) { contentView.setPadding(0, statusBarHeight, 0, 0); coordinatorLayout.post(new Runnable() { @Override public void run() { coordinatorLayout.requestLayout(); } }); } } else { coordinatorLayout.setStatusBarBackgroundColor(calculateStatusColor(color, statusBarAlpha)); } } setTransparentForWindow(activity); } }

为主Activity设置setColorForSwipeBackDrawerLayout方法,只需要把setPaddingTop删除掉就可以了,运行看效果我们发现从二级滑动返回到主Activity后底部Tab不会再上移,但是DrawerLayout不支持沉浸了,所以我们再调用一下猴子的代码 就解决了该问题。
/** * 为DrawerLayout 布局设置状态栏颜色,纯色 * * @param activity需要设置的activity * @param drawerLayout DrawerLayout * @param color状态栏颜色值 */ public static void setColorNoTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) { setColorForDrawerLayout(activity, drawerLayout, color, 0); }

最后感谢两位大佬的开源...
王浩
BGASwipeBackLayout-Android
猴子
StatusBarUtil

    推荐阅读