Android應(yīng)用中經(jīng)常會(huì)有一些要求全屏顯隱狀態(tài)欄導(dǎo)航欄的需求凹蜂。通過全屏沉浸式的處理可以讓應(yīng)用達(dá)到更好的顯示效果馍驯。下面系統(tǒng)的講解一下有關(guān)全屏,隱藏狀態(tài)欄導(dǎo)航欄玛痊,沉浸式的知識(shí)汰瘫。
在Android4.1之前只能隱藏狀態(tài)欄,在Android4.1以及之后Android提供了一套控制SystemUI的方式擂煞,重點(diǎn)放在第二部分混弥。
在Android4.1之前隱藏狀態(tài)欄
在Android4.1之前你可以通過設(shè)置WindowManager來隱藏狀態(tài)欄。你可以通過編碼來實(shí)現(xiàn)对省,也可以通過在manifest文件中給activity設(shè)置theme來實(shí)現(xiàn)蝗拿。
如果你要設(shè)置activity的狀態(tài)欄一直處于隱藏狀態(tài)晾捏,那么在manifest設(shè)置的方式是你的首選方式(盡管也可以使用編程方式。)哀托。實(shí)現(xiàn)方式如下惦辛。
<application
...
android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" >
...
</application>
使用manifest設(shè)置的方式有以下優(yōu)點(diǎn):
比編程方式更加容易維護(hù),更不容易出錯(cuò)仓手。
會(huì)有一個(gè)更加平滑的過渡胖齐,因?yàn)樵趯?shí)例化activity之前系統(tǒng)就已經(jīng)擁有了呈現(xiàn)UI所需的信息。
另外俗或,也可以以編程方式設(shè)置WindowsManager標(biāo)志市怎。這種方法使用戶在與應(yīng)用程序交互時(shí)更容易隱藏和顯示狀態(tài)欄。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// If the Android version is lower than Jellybean, use this call to hide
// the status bar.
if (Build.VERSION.SDK_INT < 16) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
setContentView(R.layout.activity_main);
}
...
}
當(dāng)你設(shè)置WindowsManager標(biāo)志時(shí)(無論是通過theme還是以編程方式)辛慰,除非您的應(yīng)用程序清除了這些標(biāo)志区匠,否則這些標(biāo)志將保持有效。
可以使用FLAG_LAYOUT_IN_SCREEN將activity布局設(shè)置為使用相同的屏幕區(qū)域帅腌。當(dāng)你啟用FLAG_FILLSCREEN時(shí)驰弄,可以使用相同的屏幕區(qū)域。這將防止在狀態(tài)欄隱藏和顯示時(shí)調(diào)整內(nèi)容的大小速客。
設(shè)置全屏
從這里開始才是本文的重點(diǎn)戚篙。
在Android4.1以及更高版本可以使用setSystemUiVisibility來控制SystemUI,為了更系統(tǒng)的講解溺职,不分別按照效果來講岔擂,而是把用到的flag先列出來一起講。以下flag經(jīng)過互相組合能達(dá)到全屏隱藏狀態(tài)欄浪耘,全屏隱藏導(dǎo)航欄乱灵,全屏顯示狀態(tài)欄導(dǎo)航欄等很多不同效果。
控制SystemBar相關(guān):
SYSTEM_UI_FLAG_FULLSCREEN
SYSTEM_UI_FLAG_HIDE_NAVIGATION
SYSTEM_UI_FLAG_LOW_PROFILE
布局相關(guān):
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
SYSTEM_UI_FLAG_LAYOUT_STABLE
沉浸式相關(guān) (4.4 引入):
SYSTEM_UI_IMMERSIVE
SYSTEM_UI_IMMERSIVE_STICKY
控制 SystemBar 相關(guān)
SYSTEM_UI_FLAG_FULLSCREEN
該屬性是用來隱藏狀態(tài)欄的七冲。
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
getSupportActionBar().hide();
通過以上代碼可以實(shí)現(xiàn)隱藏狀態(tài)欄痛倚。為了顯示出全屏效果,建議同時(shí)將ActionBar隱藏掉澜躺。僅設(shè)置這一條屬性蝉稳,顯示效果存在以下特性。
當(dāng)滑動(dòng)system bar掘鄙、點(diǎn)擊home鍵menu鍵就會(huì)清除掉flag耘戚,狀態(tài)欄會(huì)重新顯示出來。
并且布局也會(huì)隨著狀態(tài)欄的顯隱進(jìn)行布局調(diào)整進(jìn)行重繪操漠。
效果圖
SYSTEM_UI_HIDE_NAVIGATION
該屬性是用來隱藏導(dǎo)航欄的
View decorView2 = getWindow().getDecorView();
int uiOptions2 = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView2.setSystemUiVisibility(uiOptions2);
getSupportActionBar().hide();
以上代碼可以實(shí)現(xiàn)隱藏狀態(tài)欄和導(dǎo)航欄收津。
盡管可以僅僅隱藏導(dǎo)航欄,但是建議隱藏導(dǎo)航欄的時(shí)候?qū)顟B(tài)欄一并隱藏,以達(dá)到更好的沉浸效果朋截。
與隱藏狀態(tài)欄不同的是點(diǎn)擊任意布局中的任意位置都會(huì)導(dǎo)致導(dǎo)航欄導(dǎo)航欄重新顯示出來。
并且布局也會(huì)隨著狀態(tài)欄導(dǎo)航欄的顯隱進(jìn)行布局調(diào)整進(jìn)行重繪吧黄。
SYSTEM_UI_LOW_PROFILE
這個(gè)屬性的能力是讓SystemBar在視覺上變得模糊部服,重要性變得更低一點(diǎn)。具體表現(xiàn)是狀態(tài)欄圖標(biāo)僅保留電量時(shí)間關(guān)鍵圖標(biāo)拗慨,并且變暗廓八。導(dǎo)航欄圖標(biāo)變成三個(gè)點(diǎn)或者變暗。這個(gè)flag使用的很少缩麸。
View decorView7 = getWindow().getDecorView();
int uiOptions7 = View.SYSTEM_UI_FLAG_LOW_PROFILE;
decorView7.setSystemUiVisibility(uiOptions7);
布局相關(guān)
在新的Android4.1以及之后新的SystemUI設(shè)置里善延,僅單獨(dú)設(shè)置隱藏狀態(tài)欄和導(dǎo)航欄的flag會(huì)導(dǎo)致布局重繪氢烘,為了在顯隱狀態(tài)欄和導(dǎo)航欄的時(shí)候保持布局的穩(wěn)定的顯示效果,就需要以下屬性了宠叼。
SYSTEM_UI_FLAG_LAYOUT_STABLE
該flag的作用是保持布局穩(wěn)定,避免在顯隱狀態(tài)欄導(dǎo)航欄的時(shí)候發(fā)生布局的變化其爵∶岸可以輔助以下SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN、SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION兩個(gè)flag的使用摩渺,讓應(yīng)用保持全屏的情況下简烤,布局不隨狀態(tài)欄導(dǎo)航欄顯隱發(fā)生變化。也可以不配合這兩個(gè)flag使用摇幻,也能達(dá)到保持布局穩(wěn)定的效果横侦,不過不能實(shí)現(xiàn)全屏,會(huì)留出狀態(tài)欄和導(dǎo)航欄的位置绰姻。
View decorView8 = getWindow().getDecorView();
int uiOptions8 = View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView8.setSystemUiVisibility(uiOptions8);
getSupportActionBar().hide();
以上代碼設(shè)置了隱藏狀態(tài)欄和SYSTEM_UI_FLAG_LAYOUT_STABLE兩個(gè)flag枉侧,顯示效果為隱藏狀態(tài)欄,布局穩(wěn)定龙宏。但是布局不延伸到全屏棵逊,效果看起來還是很奇葩的。
當(dāng)滑動(dòng)systembar银酗、點(diǎn)擊home鍵多任務(wù)鍵就會(huì)清除掉flag辆影。狀態(tài)欄會(huì)重新顯示出來。
布局不會(huì)隨著狀態(tài)欄的顯隱進(jìn)行調(diào)整變化黍特。
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
可以讓布局延伸到狀態(tài)欄的位置蛙讥。在狀態(tài)欄在隱藏和顯示之前切換的時(shí)候,布局穩(wěn)定的顯示在狀態(tài)欄后面(如果顯示狀態(tài)欄則布局在狀態(tài)欄后面灭衷,隱藏狀態(tài)欄布局也不變)次慢。
View decorView3 = getWindow().getDecorView();
int uiOptions3 = View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView3.setSystemUiVisibility(uiOptions3);
getSupportActionBar().hide();
以上代碼顯示出來的效果和上一段代碼相比,布局延伸到了狀態(tài)欄的位置。
當(dāng)滑動(dòng)systembar迫像、點(diǎn)擊home鍵menu鍵就會(huì)清除掉flag劈愚。狀態(tài)欄會(huì)重新顯示出來。
布局不會(huì)隨著狀態(tài)欄的顯隱進(jìn)行調(diào)整變化
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
可以讓布局延伸到導(dǎo)航欄的位置闻妓【穑可以讓導(dǎo)航欄在隱藏和顯示之前切換的時(shí)候,布局穩(wěn)定的顯示在導(dǎo)航欄后面(如果顯示導(dǎo)航欄則在導(dǎo)航欄后面由缆,隱藏導(dǎo)航欄也不變)注祖。
View decorView4 = getWindow().getDecorView();
int uiOptions4 = View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView4.setSystemUiVisibility(uiOptions4);
getSupportActionBar().hide();
以上代碼的顯示效果是狀態(tài)欄和導(dǎo)航欄隱藏,布局延伸到了狀態(tài)欄和導(dǎo)航欄的位置均唉。
點(diǎn)擊任意布局就會(huì)清除掉flag是晨。狀態(tài)欄導(dǎo)航欄會(huì)重新顯示出來。
布局不會(huì)隨著狀態(tài)欄導(dǎo)航欄的顯隱進(jìn)行調(diào)整變化舔箭。
在設(shè)置了SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN罩缴、SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION flag的情況,如果把狀態(tài)欄導(dǎo)航欄顏色設(shè)置為透明层扶,則會(huì)有透明的狀態(tài)欄導(dǎo)航欄覆蓋在布局上的效果靴庆。這也證明了即便布局狀態(tài)欄導(dǎo)航欄出來了,布局也確實(shí)延伸到了狀態(tài)欄導(dǎo)航欄的位置怒医。
沉浸式相關(guān)
以上flag的組合設(shè)置中一直存在一個(gè)問題(在點(diǎn)擊Home鍵炉抒、menu鍵等操作會(huì)導(dǎo)致flag被清除,導(dǎo)航欄一點(diǎn)擊界面就會(huì)導(dǎo)致flag被清除稚叹,效果消失的問題焰薄。)。其實(shí)我們大部分情況都希望效果能夠穩(wěn)定的顯示扒袖,而不是在簡單操作之后就會(huì)消失掉塞茅。下面兩個(gè)屬性就是為這個(gè)問題工作的。
SYSTEM_UI_IMMERSIVE
在以上flag設(shè)置的基礎(chǔ)上設(shè)置該屬性季率,可以保證在點(diǎn)擊home鍵野瘦、menu鍵時(shí)不會(huì)失去狀態(tài)。但是如果手動(dòng)調(diào)出systembar的時(shí)候飒泻,設(shè)置的相關(guān)flag還是會(huì)被清除掉鞭光。
View decorView5 = getWindow().getDecorView();
int uiOptions5 = View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE;
decorView5.setSystemUiVisibility(uiOptions5);
getSupportActionBar().hide();
以上代碼的顯示效果。
隱藏狀態(tài)欄泞遗、導(dǎo)航欄惰许。
布局延伸到了狀態(tài)欄、導(dǎo)航欄的位置史辙。
布局穩(wěn)定顯示汹买,不會(huì)因?yàn)闋顟B(tài)欄的顯隱來調(diào)整布局佩伤。
當(dāng)手動(dòng)調(diào)出狀態(tài)欄導(dǎo)航欄的時(shí)候,flag才會(huì)被清除晦毙。
SYSTEM_UI_IMMERSIVE_STICKY
設(shè)置這個(gè)屬性后生巡。當(dāng)狀態(tài)欄隱藏的時(shí)候,手動(dòng)調(diào)出狀態(tài)欄導(dǎo)航欄见妒,顯示一會(huì)兒隨后就會(huì)隱藏掉障斋。設(shè)置該屬性后不會(huì)清除flag,該屬性是比較常用的一種徐鹤。但是離開頁面肯定是會(huì)導(dǎo)致flag被清除掉的,以上所有flag設(shè)置都會(huì)有這種情況邀层。
View decorView6 = getWindow().getDecorView();
int uiOptions6 = View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
decorView6.setSystemUiVisibility(uiOptions6);
getSupportActionBar().hide();
以上代碼的顯示效果返敬。
隱藏狀態(tài)欄、導(dǎo)航欄
布局延伸到了狀態(tài)欄寥院、導(dǎo)航欄的位置劲赠。
布局穩(wěn)定顯示,不會(huì)因?yàn)闋顟B(tài)欄的顯隱來調(diào)整布局秸谢。
手動(dòng)調(diào)出的狀態(tài)欄導(dǎo)航欄會(huì)半透明顯示覆蓋在界面上凛澎,隨后還會(huì)隱藏掉。
如果離開頁面還是會(huì)導(dǎo)致flag被清除估蹄,效果消失塑煎。
對于flag被清除問題,重設(shè)的位置可以放在onWindowFocusChanged中臭蚁。
想要清除flag可以直接調(diào)用setSystemUiVisibility(0);
小總結(jié)
有了以上flag的總結(jié)最铁,我們可以實(shí)現(xiàn)我們想要的一些效果。比如全屏隱藏狀態(tài)欄導(dǎo)航欄垮兑、全屏顯示導(dǎo)狀態(tài)欄導(dǎo)航欄冷尉、全屏顯示狀態(tài)欄隱藏導(dǎo)航欄、全屏隱藏狀態(tài)欄顯示導(dǎo)航欄系枪,甚至組合出非全屏但是隱藏狀態(tài)欄導(dǎo)航欄等一些奇葩的顯示效果雀哨。下面用一段代碼展示一下全屏中的各中顯示效果,也是我們項(xiàng)目常用的效果私爷。
public void setFullscreen(boolean isShowStatusBar, boolean isShowNavigationBar) {
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
if (!isShowStatusBar) {
uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN;
}
if (!isShowNavigationBar) {
uiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
}
getWindow().getDecorView().setSystemUiVisibility(uiOptions);
//隱藏標(biāo)題欄
getSupportActionBar().hide();
//專門設(shè)置一下狀態(tài)欄導(dǎo)航欄背景顏色為透明雾棺,凸顯效果。
setNavigationStatusColor(Color.TRANSPARENT);
}
public void setNavigationStatusColor(int color) {
//VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
if (Build.VERSION.SDK_INT >= 21) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().setNavigationBarColor(color);
getWindow().setStatusBarColor(color);
}
}
監(jiān)聽狀態(tài)欄導(dǎo)航欄的變化
有時(shí)候我們想知道狀態(tài)欄衬浑、導(dǎo)航欄的顯隱變化垢村,便于我們自定義一些操作。Android也提供了一個(gè)監(jiān)聽變化的能力嚎卫。
View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
(new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
// Note that system bars will only be "visible" if none of the
// LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
// TODO: The system bars are visible. Make any desired
// adjustments to your UI, such as showing the action bar or
// other navigational controls.
} else {
// TODO: The system bars are NOT visible. Make any desired
// adjustments to your UI, such as hiding the action bar or
// other navigational controls.
}
}
});
上面代碼和注釋可以說寫的很清楚了嘉栓『觊牛可以在onSystemUiVisibilityChange接口中通過判斷LOW_PROFILE,HIDE_NAVIGATION和FULLSCREEN的值來看顯隱侵佃,0為顯示麻昼,1為隱藏。
最后
如果閱讀過程中發(fā)現(xiàn)有什么問題馋辈,歡迎交流指正抚芦。打完,收工迈螟!
Task is cheap. Show me the code. github地址: https://github.com/qiaoshouqing/fullscreen
內(nèi)容主要參考谷歌官方文檔叉抡,不得不說文章還是原生的好,在國內(nèi)很難搜到好用的文章答毫。 https://developer.android.com/training/system-ui/index.html
后來發(fā)現(xiàn)國內(nèi)有人翻譯過了褥民,文章寫作方式上有參考。https://blog.csdn.net/adzcsx2/article/details/53031950
歡迎關(guān)注~~~
歡迎關(guān)注【Funny新青年】微信公眾號~