您好,登錄后才能下訂單哦!
關于所謂的“沉浸式”,我有許多話要說,因為這個東西實在是折磨了我許多的時間。實現的方式有許多,兼容性問題也不少。官方文檔也讓我感到也有些云里霧里。那些“長得很相似”的Flag,適用情況很接近的設置方法,讓我不得不一個個測試,然而卻一次次推翻。模擬器上測試;真機上測試;4.4版本上的測試;5.0后版本的測試;有導航欄手機上的測試;老掉牙手機上的測試。總而言之,這個東西的探索讓我深刻地體會到android系統兼容性問題的麻煩。
當你功能開發占據10%,而處理兼容性問題占據90%的時候。你不得不思考這樣一個問題:“兼容性真的有那么重要嗎?”撇開這個問題,以投入和產出的角度顯然是不太劃得來的,但是收獲的角度:我學習了解了View的加載機制、DecorView在不同版本上的實現以及發展、養成了遇到問題第一時間查閱官方文檔的習慣。
關鍵詞
1、系統欄Systembar(包括狀態欄Statusbar,導航欄Navigationbar)
2、內容主體暫且可以理解為Window中除了Systembar以外的窗口
實現原理:
1、將SystemBar透明化
2、根據不同情況決定內容主體是否需要延伸到SystemBar下方
一、將SystemBar透明化
主題中設置屬性:
<itemname="android:windowTranslucentStatus">true</item>
<itemname="android:windowTranslucentNavigation">true</item>
代碼中設置Flag:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//透明狀態欄
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);//透明導航欄
5.0后設置:
getWindow().setStatusBarColor(Color.TRANSPARENT);
getWindow().setNavigationBarColor(Color.TRANSPARENT);
二、根據不同情況決定內容主體是否需要延伸到SystemBar下
主題中設置屬性:
<itemname="android:windowFullscreen">true</item>
代碼中設置Flag:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
FLAG_TRANSLUCENT_STATUS單獨使狀態欄透明化
FLAG_TRANSLUCENT_NAVIGATION單獨使導航欄透明化
4.1后更多選項的設置:
ViewdecorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(Flag);
Flag的值需要了解以下幾種情況:
1、SYSTEM_UI_FLAG_FULLSCREEN
2、SYSTEM_UI_FLAG_HIDE_NAVIGATION
3、SYSTEM_UI_FLAG_IMMERSIVE
4、SYSTEM_UI_FLAG_IMMERSIVE_STICKY
5、SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
6、SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
7、SYSTEM_UI_FLAG_LAYOUT_STABLE
8、SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
SYSTEM_UI_FLAG_FULLSCREEN
隱藏狀態欄,主體向上偏移,但在手動下拉會重新顯示狀態欄并清除該flag。
View.SYSTEM_UI_FLAG_FULLSCREEN |View.SYSTEM_UI_FLAG_LAYOUT_STABLE
限制主體位置保持不變,狀態欄留白
SYSTEM_UI_FLAG_HIDE_NAVIGATION
隱藏導航欄,主體向下偏移,由于導航欄太重要了,所以只要和Activity進行任何交互都會重新顯示導航欄,并清除該flag和SYSTEM_UI_FLAG_FULLSCREEN。
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
限制主體位置保持不變,導航欄留白
SYSTEM_UI_FLAG_LAYOUT_STABLE
保持內容主體位置不變,不隨著Systembar的隱藏顯示而偏移
SYSTEM_UI_FLAG_IMMERSIVE
沉浸模式:只能和SYSTEM_UI_FLAG_HIDE_NAVIGATION結合使用。簡單交互不會重新顯示導航欄
SYSTEM_UI_FLAG_IMMERSIVE_STICKY
沉浸模式:只能和SYSTEM_UI_FLAG_FULLSCREEN或SYSTEM_UI_FLAG_HIDE_NAVIGATION結合使用。
下拉狀態欄位置可以短暫顯示狀態欄和導航欄,然后再次隱藏。
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
主體占據全部屏幕,但不隱藏狀態欄,這里的layout可以理解為內容主體
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
主體占據全部屏幕,但不隱藏導航欄,這里的layout可以理解為內容主體
SYSTEM_UI_FLAG_LAYOUT_STABLE
這個Flag確實有點難以理解,唯一讀懂的是在各種flag切換的時候能保持內容主體的穩定性。如果你不想flag變換的時候內容主體上下偏移,就需要設置SYSTEM_UI_FLAG_LAYOUT_STABLE。
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
淺色狀態欄模式:對應于圖標變深色,防止淺色背景導致狀態欄看不清,不設置是深色模式
實踐驗證過程:
View decorView =getWindow().getDecorView();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
狀態欄不會隱藏,仍占據著位置,但內容可以侵入狀態欄下方
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
View.SYSTEM_UI_FLAG_FULLSCREEN 狀態欄下滑,主體布局就會下降一個狀態欄的高度,很突兀
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN狀態欄下滑,主體布局位置不變化
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
這個和單獨使用View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN區別在哪兒,還沒發現
andriod系統提供了一些透明狀態欄/導航欄的主題以供使用:
<stylename="Theme.Material.Light.NoActionBar.TranslucentDecor">
<item name="windowTranslucentStatus">true</item>
<itemname="windowTranslucentNavigation">true</item>
<itemname="windowContentOverlay">@null</item>
</style>
SYSTEM_UI_FLAG_HIDE_NAVIGATION |SYSTEM_UI_FLAG_IMMERSIVE
SYSTEM_UI_FLAG_IMMERSIVE必須與SYSTEM_UI_FLAG_HIDE_NAVIGATION 結合使用才有意義
加上SYSTEM_UI_FLAG_IMMERSIVE,則導航欄在隱藏后不會因與界面的交互而呼出。
類似于看視頻時進入全屏模式。
SYSTEM_UI_FLAG_FULLSCREEN |SYSTEM_UI_FLAG_HIDE_NAVIGATION
進入全屏模式,但用戶與界面進行最簡單的交互都會重新顯示狀態欄,導航欄
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE
進入全屏模式,用戶交互會重新顯示狀態欄,導航欄,不會再隱藏
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION| View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
進入全屏模式,用戶交互會短暫顯示狀態欄,導航欄,然后再隱藏
總結:
比較簡潔的透明狀態欄的做法是:
方法一:適合4.1及以上
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP){
View window =getWindow().getDecorView();
window.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
對于不需要延伸至狀態欄下方的組件,使用android:fitsSystemWindows="true"將進行設置即可。本質上是添加一個狀態欄高度的paddingTop屬性,所以android:layout_height屬性不要使用"250dp"這種固定數值,可以使用"wrap_content"結合android:minHeight="250dp"的方式。
方法二:適合4.1及以上
同方法一:
<itemname="android:windowTranslucentStatus">true</item>
<itemname="android:windowTranslucentNavigation">true</item>
結合android:fitsSystemWindows屬性
方法三:適合4.0及以下的版本
<itemname="android:windowFullscreen">true</item>
<itemname="android:windowContentOverlay">@null</item>
或者代碼中:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
方法三使用android:fitsSystemWindows是無效的。所以我的做法是給需要向下偏移的組件設置一個paddingTop的值,并在v21,v19等不同版本設置不同的值做兼容(源碼可知statusbar高度是25dp)。這里默認所有手機平臺都是25dp。
網上的做法是選擇性填充一個View,該View的Height是動態獲取的statusbar的高度。這個做法兼容了不同廠商自己定制的UI使用不同于Google官方25dp的狀態欄高度的情況。如紅米note2是20dp,魅族note5是22dp。
另外對于setFlags方法,同樣有單獨設置狀態欄和導航欄的方法:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
對于這兩個屬性而言,android:fitsSystemWindows有效,但在設置了FLAG_TRANSLUCENT_NAVIGATION的時候,內容主體也會向下偏移一個導航欄的高度,可見這里的android:fitsSystemWindows指的是SystemBar,而不僅僅是StatusBar。
方法四:適合于5.0以后
結合Design Support庫中的CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout,并且結合使用fitsSystemWindows。這也是我第一個接觸的方法。需要注意的是fitsSystemWindows屬性在CoordinatorLayout中有不同的實現,fitsSystemWindows=“true”反而表示是否出現在狀態欄下方。知道真相的我眼淚掉下來。
方法在Fragment中會有問題(例如在FragmentTabhost中使用),使用replace切換則正常,使用add切換的Fragment則fitSystemWindow失效,必須調用onCreate才能生效,我滴個天~~~~最后我只能放棄fitSystemWindow,使用方法三中的設置paddingTop的方法。
方法五:使用第三方框架
SystemBarTint https://github.com/jgilfelt/SystemBarTint
StatusBarUtil https://github.com/laobie/StatusBarUtil
備注:
使用Theme的方式相比代碼中設置的優勢:
1、更易于維護,并且不易出錯
2、更順暢的UI過渡,因為系統在初始化主Activity之前就已經知道了渲染UI所需要的相關信息
參考資料:
Managing the System UI
https://developer.android.com/training/system-ui/index.html
SystemBarTint
https://github.com/jgilfelt/SystemBarTint
StatusBarUtil
https://github.com/laobie/StatusBarUtil
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。