背景
在寫(xiě)Reading的過(guò)程中,想實(shí)現(xiàn)仿IOS右滑關(guān)閉Activity的效果,在網(wǎng)上找到了BGASwipeBackLayout-Android
,看著效果不錯(cuò),剛巧這個(gè)庫(kù)也使用的猴子的StatusBarUtil
,在使用的過(guò)程中,效果確實(shí)不錯(cuò),同時(shí)這個(gè)庫(kù)也支持了右滑關(guān)閉Activity時(shí)候沉浸式通知欄,但是Reading里面用到了DrawerLayout,結(jié)合BGASwipeBackLayout-Android使用的時(shí)候出現(xiàn)了下面的問(wèn)題,就是當(dāng)從主Activity進(jìn)入二層界面再返回的時(shí)候,底部Tab會(huì)彈一下再上來(lái),效果有些炸眼....

解決
想要解決這個(gè)問(wèn)題無(wú)非從兩個(gè)角度去思考
- BGASwipeBackLayout-Android
- StatusBarUtil
浩哥的BGA是通過(guò)修改support-v4 包中 SlidingPaneLayout 的源碼來(lái)實(shí)現(xiàn)滑動(dòng)返回布局,源碼在BGASwipeBackLayout.java這里,大概過(guò)了一下,感覺(jué)還是挺復(fù)雜的。放棄了,然后通過(guò)查看浩哥支持的為滑動(dòng)界面設(shè)置狀態(tài)欄顏色的方法
/**
* 為滑動(dòng)返回界面設(shè)置狀態(tài)欄顏色
*
* @param activity 需要設(shè)置的activity
* @param color 狀態(tài)欄顏色值
*/
public static void setColorForSwipeBack(Activity activity, int color) {
setColorForSwipeBack(activity, color, DEFAULT_STATUS_BAR_ALPHA);
}
/**
* 為滑動(dòng)返回界面設(shè)置狀態(tài)欄顏色
*
* @param activity 需要設(shè)置的activity
* @param color 狀態(tài)欄顏色值
* @param statusBarAlpha 狀態(tài)欄透明度
*/
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);
}
}
這段代碼我們可以看到通過(guò)獲取根布局,如果跟布局是CoordinatorLayout的話,設(shè)置paddingTop,并且設(shè)置顏色重繪。否則給contentView設(shè)置了paddingTop并且設(shè)置顏色。參考這段代碼,我們找到了猴子的為DrawerLayout提供的沉浸式代碼
/**
* 為DrawerLayout 布局設(shè)置狀態(tài)欄變色
*
* @param activity 需要設(shè)置的activity
* @param drawerLayout DrawerLayout
* @param color 狀態(tài)欄顏色值
* @param statusBarAlpha 狀態(tài)欄透明度
*/
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);
}
// 生成一個(gè)狀態(tài)欄大小的矩形
// 添加 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);
}
// 內(nèi)容布局不是 LinearLayout 時(shí),設(shè)置padding top
if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {
contentLayout.getChildAt(1)
.setPadding(contentLayout.getPaddingLeft(), getStatusBarHeight(activity) + contentLayout.getPaddingTop(),
contentLayout.getPaddingRight(), contentLayout.getPaddingBottom());
}
// 設(shè)置屬性
setDrawerLayoutProperty(drawerLayout, contentLayout);
addTranslucentView(activity, statusBarAlpha);
}
從代碼來(lái)看,一眼看到代碼注釋//生成一個(gè)狀態(tài)欄大小的矩形,也就是說(shuō)支持DrawerLayout沉浸的原理是為跟布局設(shè)置 android:fitsSystemWindows="true",讓整個(gè)屏幕都可以放組件,同時(shí)加了一個(gè)狀態(tài)欄大小的矩形,并設(shè)置了顏色,這樣就滿足了DrawerLayout的沉浸式。
- 1.fitsSystemWindow 默認(rèn)是true,就是組件都在屏幕內(nèi),但是不包括statusBar。設(shè)置成false后,整個(gè)屏幕都可以放置組件,沒(méi)有statusBar和window之分。
- 2.android:fitsSystemWindows=“true”在布局中占有最高權(quán)限,如果明確設(shè)置為true,style設(shè)置fits為false是無(wú)效的;同理,只在布局中設(shè)置fits而沒(méi)有設(shè)置style也是無(wú)效的。
好了,分析到這里我們不難想出來(lái)解決辦法了,從浩哥提供的滑動(dòng)關(guān)閉界面的沉浸代碼中可以看到滑動(dòng)關(guān)閉的Activity并沒(méi)有設(shè)置android:fitsSystemWindows="true",那么這個(gè)Activity是有statusBar和window的區(qū)分的,通過(guò)設(shè)置了paddingTop來(lái)實(shí)現(xiàn)的,而猴子的setDrawerLayout支持的前提是為跟布局設(shè)置了android:fitsSystemWindows="true",也就是沒(méi)有了statusBar,所以最終看到的效果就是上面的動(dòng)態(tài)圖,進(jìn)入二級(jí)界面為了實(shí)現(xiàn)左滑界面的沉浸式,設(shè)置了浩哥的setColorForSwipeBack方法,當(dāng)返回到主Activity時(shí),由于主界面沒(méi)有了statusBar,所以你會(huì)看到底部的tab會(huì)向上移動(dòng)了一個(gè)statusBar的高度,最后解決的代碼如下:
/**
* 為滑動(dòng)返回界面設(shè)置狀態(tài)欄顏色
*
* @param activity 需要設(shè)置的activity
* @param color 狀態(tài)欄顏色值
* @param statusBarAlpha 狀態(tài)欄透明度
*/
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設(shè)置setColorForSwipeBackDrawerLayout方法,只需要把setPaddingTop刪除掉就可以了,運(yùn)行看效果我們發(fā)現(xiàn)從二級(jí)滑動(dòng)返回到主Activity后底部Tab不會(huì)再上移,但是DrawerLayout不支持沉浸了,所以我們?cè)僬{(diào)用一下猴子的代碼 就解決了該問(wèn)題。
/**
* 為DrawerLayout 布局設(shè)置狀態(tài)欄顏色,純色
*
* @param activity 需要設(shè)置的activity
* @param drawerLayout DrawerLayout
* @param color 狀態(tài)欄顏色值
*/
public static void setColorNoTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {
setColorForDrawerLayout(activity, drawerLayout, color, 0);
}
最后感謝兩位大佬的開(kāi)源...