Android右滑退出+沉浸式(透明)狀態(tài)欄

背景

上篇文章一個(gè)千萬量級(jí)的APP使用的一些第三方庫中,在說到一個(gè)使用很廣泛的滑動(dòng)退出庫SwipeBackLayout時(shí)有提過有時(shí)間會(huì)分享自己在項(xiàng)目中引入這個(gè)庫的時(shí)候填過的一些坑。前段時(shí)間項(xiàng)目加入沉浸式狀態(tài)欄效果的時(shí)候也走了不少?gòu)澛罚覂烧呓Y(jié)合效果還不錯(cuò),就一起分享出來了。
先上效果圖:

右滑退出+沉浸式(透明)狀態(tài)欄效果.gif

一、添加 SwipeBackLayout

compile 'me.imid.swipebacklayout.lib:library:1.0.0'

step1:BaseActivity

新建一個(gè)繼承SwipeBackActivity的BaseActivity類,SwipeBackActivity的代碼請(qǐng)看SwipeBackLayout庫源碼,在onCreate方法內(nèi)添加如下兩行代碼。所有繼承BaseActivity的頁面都能具有滑動(dòng)效果了。但比如登錄頁和主頁面等部分不需要右滑效果的Activity可以通過setSwipeBackEnable(false)方法禁用右滑效果。

 mSwipeBackLayout = getSwipeBackLayout();
 // 設(shè)置滑動(dòng)方向,可設(shè)置EDGE_LEFT, EDGE_RIGHT, EDGE_ALL,EDGE_BOTTOM
 mSwipeBackLayout.setEdgeTrackingEnabled(SwipeBackLayout.EDGE_LEFT);

step2:設(shè)置theme

在style.xml文件中添加以下代碼

 <!-- 設(shè)置右滑主題 -->
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">    
<item name="android:windowAnimationStyle">@style/HoloThemeActivityAnimation</item>    
<!-- 設(shè)置背景透明,右滑時(shí)才能看到上一個(gè)界面,否則會(huì)看到黑屏效果-->, 
<item name="android:windowIsTranslucent">true</item>
</style>

<!--Activity退出動(dòng)畫-->
<style
 name="HoloThemeActivityAnimation" parent="@android:style/Animation.Activity">   
 <item name="android:activityOpenEnterAnimation">@anim/activity_open_enter</item>
 <item name="android:activityOpenExitAnimation">@anim/activity_open_exit</item> 
 <item name="android:activityCloseEnterAnimation">@anim/activity_close_enter</item>  
 <item name="android:activityCloseExitAnimation">@anim/activity_close_exit</item>
 </style>

<!--主界面單獨(dú)設(shè)置以下主題,不透明,否則右滑不是顯示上一個(gè)頁面而是直接顯示桌面了~-->
<style name="AppThemeNoTranslucent" parent="Theme.AppCompat.DayNight.NoActionBar">    
<item name="android:windowNoTitle">true</item>  
<item name="android:windowIsTranslucent">false</item>    
</style>

step3:AndroidManifest

在AndroidManifest文件中 application節(jié)點(diǎn)設(shè)置全局主題
android:theme="@style/AppTheme"。
主界面單獨(dú)設(shè)置不透明主題
android:theme="@style/AppThemeNoTranslucent"。

二、加入沉浸式狀態(tài)欄效果

先上效果圖:

效果圖.png

關(guān)于沉浸式狀態(tài)欄這個(gè)資料現(xiàn)在很多,但感覺很多介紹的并不全面,我自己也試過挺多方法后才有了目前這個(gè)方案。

step1:首先得設(shè)置狀態(tài)欄透明

關(guān)于狀態(tài)欄透明最開始用的是以下方法,這也是目前在網(wǎng)上看到的比較多的一種方法,但是后來發(fā)現(xiàn)在部分5.0以上系統(tǒng)上會(huì)有兼容性問題:

//以下方案在部分5.0以上手機(jī)內(nèi)會(huì)有兼容性問題,會(huì)有一個(gè)半透明的背景附在狀態(tài)欄位置上
final int sdk = Build.VERSION.SDK_INT;
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
if (sdk >= Build.VERSION_CODES.KITKAT) {    
   int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;    // 設(shè)置透明狀態(tài)欄
   if ((params.flags & bits) == 0) {      
   params.flags |= bits;       
   window.setAttributes(params);   
   }
 }

發(fā)現(xiàn)這個(gè)問題在百度音樂和360衛(wèi)士等APP上也是存在的,看以下兩個(gè)截圖。(可能我的測(cè)試機(jī)有點(diǎn)非主流~,在小米,華為等主流手機(jī)上以上方法和這兩個(gè)APP測(cè)試都正常)

百度音樂.png
360手機(jī)衛(wèi)士.png

后來在Android 系統(tǒng)狀態(tài)欄沉浸式/透明化完整解決方案這篇文章的評(píng)論內(nèi)下面發(fā)現(xiàn)了下面這個(gè)方法??梢詫?shí)現(xiàn)完美的狀態(tài)欄透明效果。

//最終方案
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {    
//5.0 全透明實(shí)現(xiàn)
//getWindow.setStatusBarColor(Color.TRANSPARENT)
Window window = getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);    
window.setStatusBarColor(Color.TRANSPARENT);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {    
 //4.4 全透明狀態(tài)欄
 getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}

step2:設(shè)置標(biāo)題欄的高度

狀態(tài)欄透明后本來以為這事情差不多了,不過事實(shí)證明這僅僅是另外一個(gè)坑的開始。
設(shè)置狀態(tài)欄透明后,ToolBar(或者自定義的titleBar)就會(huì)跑到StatusBar下面,如圖1。處理這個(gè)問題有兩個(gè)思路。一個(gè)是為ToolBar頂部設(shè)置一個(gè)高度和狀態(tài)欄一樣的padding或margin。第二個(gè)是在根布局設(shè)置android:fitsSystemWindows="true"屬性,然后新建一個(gè)和ToolBar背景色一樣的View添加到原來狀態(tài)欄的位置(或者直接在根布局設(shè)置一個(gè)和ToolBar一樣的背景色,不過測(cè)試時(shí)發(fā)現(xiàn)這個(gè)方法在有DrawerLayout時(shí)好像不管用)。

圖1.png

第一種方法

為ToolBar頂部設(shè)置一個(gè)高度和狀態(tài)欄一樣的padding或margin

1.1 一個(gè)坑

最開始我使用的是第一種方法,在ToolBar外面套一層布局,然后為ToolBar設(shè)置頂部margin。但是發(fā)現(xiàn)了一個(gè)很奇葩的問題,在4.4以上系統(tǒng)上底部聊天及評(píng)論框不能被系統(tǒng)輸入法頂上去。如下圖2(圖片引用自另外兩種android沉浸式狀態(tài)欄實(shí)現(xiàn)思路,關(guān)于這個(gè)問題更詳細(xì)的描述也可以點(diǎn)擊此鏈接)。

圖2.png

原因是因?yàn)樵O(shè)置狀態(tài)欄透明后得設(shè)置android:fitsSystemWindows="true"這個(gè)屬性。當(dāng)時(shí)我的解決辦法是使用AndroidBug5497Workaround 動(dòng)態(tài)計(jì)算布局的高度。這個(gè)方法在華為等手機(jī)上存在兼容性問題。我在源碼的基礎(chǔ)上做了一些修改,修改后的效果在華為,小米,三星等手機(jī)上測(cè)試均正常。修改后的代碼看我另外一篇文章關(guān)于AndroidBug5497Workaround方法的兼容性問題

1.2 含有DrawerLayout+NavigationView

這里還要注意的一個(gè)問題是如果頁面含有DrawerLayout,而且側(cè)滑菜單欄使用的是NavigationView,記得給NavigationView加上app:insetForeground="#00000000"。否則側(cè)滑時(shí)會(huì)出現(xiàn)一個(gè)半透明的狀態(tài)欄。如下圖3。

圖3.png
1.3 兼容4.4

另外就是在4.4系統(tǒng)上如果使用DrawerLayout+NavigationView,在NavigationView上會(huì)出現(xiàn)下圖4情況。解決辦法如下(參考自Android 系統(tǒng)狀態(tài)欄沉浸式/透明化完整解決方案):

 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { 
 //將側(cè)邊欄頂部延伸至status bar    
  drawer.setFitsSystemWindows(true);  
 //將主頁面頂部延伸至status bar;雖默認(rèn)為false,但經(jīng)測(cè)試,DrawerLayout需顯示設(shè)置  
  drawer.setClipToPadding(false);
}
圖4.png

第二種方法

在根布局設(shè)置android:fitsSystemWindows="true"屬性,然后新建一個(gè)和ToolBar背景色一樣的View添加到原來狀態(tài)欄的位置(或者直接在根布局設(shè)置一個(gè)和ToolBar一樣的背景色,不過測(cè)試時(shí)發(fā)現(xiàn)這個(gè)方法在有DrawerLayout時(shí)好像不管用)

2.1 什么是fitsSystemWindows

使用第二種方法前我們有必要先了解下fitsSystemWindows這個(gè)屬性是什么。

System windows 指的就是屏幕上status bar、 navigation bar等系統(tǒng)控件所占據(jù)的部分。

android:fitsSystemWindows="true" 這個(gè)屬性的作用就是通過設(shè)置View的padding,使得應(yīng)用的content部分——Activity中setContentView()中傳入的就是content——不會(huì)與system window重疊。

這個(gè)屬性的詳細(xì)介紹看這里為什么我們要用fitsSystemWindows

2.2 封裝好的代碼

“新建一個(gè)和ToolBar一樣背景色的View添加到原來狀態(tài)欄的位置” 的代碼如下(參考自Android 沉浸狀態(tài)欄):

public static void setStateBarColor(Activity activity) {    
// 設(shè)置狀態(tài)欄顏色    
ViewGroup contentLayout = (ViewGroup) activity.findViewById(android.R.id.content);
setupStatusBarView(activity, contentLayout, Color.parseColor("#FF5677FC"));  
 // 設(shè)置Activity layout的fitsSystemWindows    
View contentChild = contentLayout.getChildAt(0);   
contentChild.setFitsSystemWindows(true);//等同于在根布局設(shè)置android:fitsSystemWindows="true"
}

private static void setupStatusBarView(Activity activity, ViewGroup contentLayout, int color) { 
 View mStatusBarView = null;   
 View statusBarView = new View(activity);    
 ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));   
 contentLayout.addView(statusBarView, lp);   
 mStatusBarView = statusBarView;   
 mStatusBarView.setBackgroundColor(color);
}

/** * 獲得狀態(tài)欄高度 */
private static int getStatusBarHeight(Context context) {  
 int resourceId =context.getResources().getIdentifier("status_bar_height", "dimen", "android");   
 return context.getResources().getDimensionPixelSize(resourceId);
}

使用方法:
在相應(yīng)Activity中調(diào)用setStateBarColor(activity)方法即可。

2.3 缺陷

但是這種方法有個(gè)缺陷是在DrawerLayout上當(dāng)側(cè)滑菜單NavigationView滑出來時(shí)狀態(tài)欄會(huì)浮在上面。如下圖3。目前并未找到解決方案。

圖3.png

總結(jié):

可以看到兩種方式都不算是完美,實(shí)際項(xiàng)目中可以根據(jù)需要選擇合適的方式。
1.有DrawerLayout時(shí)優(yōu)先選擇第一種為ToolBar設(shè)置Padding或Margin的方式。
2.底部有輸入框的聊天和評(píng)論界面優(yōu)先選擇在根布局設(shè)置android:fitsSystemWindows="true"屬性,然后新建一個(gè)和ToolBar一樣背景色的View添加到原來狀態(tài)欄的位置的方式。當(dāng)然你也可以選擇統(tǒng)一用第一種方式,然后使用AndroidBug5497Workaround動(dòng)態(tài)調(diào)整輸入框的位置。

最后

源碼已上傳到GitHub點(diǎn)擊查看。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容