//DecorView獲取
Activity.getWindow().getDecorView()
//DecorView獲取contentView
Activity.findViewById(android.R.id.content)
//獲取activity的 setContentView(int LayoutXml);//即我們xml里面寫(xiě)的xml布局
ViewGroup rootView = (ViewGroup) content.getChildAt(0);
全屏化一般用在啟動(dòng)頁(yè):
參考:http://blog.csdn.net/lu_ca/article/details/72778694
requestWindowFeature(Window.FEATURE_NO_TITLE);// 隱藏標(biāo)題
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);// 設(shè)置全屏
setContentView(R.layout.activity_main);
注意:setContentView一定要寫(xiě)在設(shè)置全屏后邊
沉浸式的一般套路
在Android上,關(guān)于對(duì)StatusBar(狀態(tài)欄)的操作掌动,一直都在不斷改善沟优,并且表現(xiàn)越來(lái)越好,在Android4.4 以下府瞄,我們可以對(duì)StatusBar和 NavigationBar進(jìn)行顯示和隱藏操作冲呢。但是直到Android4.4,我們才能真正意義上的實(shí)現(xiàn)沉浸式狀態(tài)欄。從Android4.4 到現(xiàn)在(Android 7.1)妇多,關(guān)于沉浸式大概可以分成三個(gè)階段:
Android4.4(API 19) - Android 5.0(API 21): 這個(gè)階段可以實(shí)現(xiàn)沉浸式贤惯,但是表現(xiàn)得還不是很好洼专,實(shí)現(xiàn)方式為: 通過(guò)
FLAG_TRANSLUCENT_STATUS
設(shè)置狀態(tài)欄為透明并且為全屏模式,這個(gè)時(shí)候布局會(huì)入侵狀態(tài)欄孵构,我們可以通過(guò)添加一個(gè)與StatusBar 一樣大小的View屁商,將View 的 background 設(shè)置為我們想要的顏色,從而來(lái)實(shí)現(xiàn)沉浸式颈墅。Android 5.0(API 21)以上版本: 在Android 5.0的時(shí)候蜡镶,加入了一個(gè)重要的屬性和方法 android:statusBarColor (對(duì)應(yīng)方法為 setStatusBarColor),通過(guò)這個(gè)方法我們就可以輕松實(shí)現(xiàn)沉浸式恤筛。也就是說(shuō)官还,從Android5.0開(kāi)始,系統(tǒng)才真正的支持沉浸式毒坛。
Android 6.0(API 23)以上版本:其實(shí)Android6.0以上的實(shí)現(xiàn)方式和Android 5.0 +是一樣望伦,為什么要將它歸為一個(gè)單獨(dú)重要的階段呢?是因?yàn)閺腁ndroid 6.0(API 23)開(kāi)始煎殷,我們可以改狀態(tài)欄的繪制模式屯伞,
SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
可以顯示白色或淺黑色的內(nèi)容和圖標(biāo)(除了魅族手機(jī),魅族自家有做源碼更改豪直,6.0以下就能實(shí)現(xiàn))
-
代碼未行劣摇,效果先上
-
Android4.4(API 19) - Android 5.0(API 21)如何實(shí)現(xiàn)
在 [KITKAT][null-link] 之后,Android Window支持了一些新的屬性弓乙,4.4以上能設(shè)置沉浸狀態(tài)欄末融,正是因?yàn)橄旅娴膄lag引入了,通過(guò)這兩個(gè)flag可以設(shè)置Status Bar或Nav Bar透明唆貌。設(shè)置這個(gè)屬性不做其他操作一定會(huì)入侵狀態(tài)欄
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
和 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCRE
這兩個(gè)flag會(huì)被自動(dòng)添加到system UI visibility中滑潘。
正如它們的變量名的意思,使用這兩個(gè)屬性锨咙,可以使得狀態(tài)欄和導(dǎo)航欄變?yōu)橥该鳎瑢?dǎo)航欄指的就是Android下方的三大按鍵追逮,當(dāng)然只使用第一個(gè)屬性也可以達(dá)到今天所要完成的效果酪刀。下面的示例代碼將使?fàn)顟B(tài)欄和導(dǎo)航欄變得透明
我們注意到上面的flag名為TRANSLUCENT粹舵,而不是TRANSPARENT, 知乎 指出了骂倘,TranslucentStatus 在 4.4 和 5.x 上表現(xiàn)不同眼滤,4.4 是一層漸變的遮罩層,5.x 以上是一條半透明的遮罩層(5.0以上不建議用這個(gè)方法历涝,下面有詳解)诅需,比如Genymotion模擬器上就是這樣,但在一些其他機(jī)器比如小米上荧库,就是全透明的堰塌,這應(yīng)該是和系統(tǒng)有關(guān)的。
Genymotion模擬器4.4上透明狀態(tài)欄的效果:
小米4.4上透明狀態(tài)欄的效果:
Genymotion模擬器5.x上透明狀態(tài)欄的效果:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initWindow();
}
@TargetApi(19)
private void initWindow(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
直接運(yùn)行之后分衫,狀態(tài)欄直接透明了场刑,但是并不是我們想要的效果。當(dāng)設(shè)置Status Bar透明后蚪战,由于visibility flag的自動(dòng)添加牵现,屏幕會(huì)變成全屏的。所以這時(shí)候ToolBar就直接跑到StatusBar下面了邀桑,如圖:
這個(gè)問(wèn)題也很好解決瞎疼,在 style theme 添加,或者Activity的layout的屬性android:fitsSystemWindows="true",但是發(fā)現(xiàn)壁畸,StatusBar變灰色了丑慎。(那是xml里面主布局的顏色,因?yàn)閒itsSystemWindows是設(shè)置padding的瓤摧,其實(shí)只需要把xml主布局顏色設(shè)置了就不會(huì)變灰了)
小結(jié):
Android4.4上實(shí)現(xiàn)沉浸式狀態(tài)欄的套路是:為window添加FLAG_TRANSLUCENT_STATUS Flag
- 方法1.往DecorView添加一個(gè)和status bar 一樣大小的View 站位竿裂,然后添加setFitsSystemWindows從而讓讓標(biāo)題欄不會(huì)與status bar 重疊。(因?yàn)镈ecorView是framlayout即使加View也不行把contenView頂下來(lái)照弥,所以contenView增加setFitsSystemWindows屬性會(huì)自定增加status bar的高度)即上面演示的代碼腻异。
- 方法2.不加VIew,直接手動(dòng)設(shè)置xml里面的主布局padding屬性為statusView的高度这揣。(不要設(shè)置margin會(huì)出現(xiàn)狀態(tài)欄變成灰色)
- 方法3.最簡(jiǎn)單悔常,直接設(shè)置setFitsSystemWindows后,設(shè)置主布局顏色為標(biāo)題欄顏色就可以了给赞。但是這樣的做法不能解決圖片問(wèn)題沉浸式問(wèn)題机打。
- 若:而圖片延伸到狀態(tài)欄只需要設(shè)置FLAG_TRANSLUCENT_STATUS就OK
ps:
android:clipChildren:clipChildren表示是否限制子View在其范圍內(nèi),默認(rèn)true
android:clipToPadding:ClipToPadding用來(lái)定義ViewGroup是否允許在padding中繪制片迅。默認(rèn)情況下残邀,cliptopadding被設(shè)置為ture, 也就是把padding中的值都進(jìn)行裁切了,如圖片超出邊界后被裁剪芥挣。默認(rèn)true
-
2.2 Android 5.0(API 21)以上實(shí)現(xiàn)沉浸式的方式
google 加入了一個(gè)比較重要的方法setStatusBarColor (對(duì)應(yīng)屬性:android:statusBarColor)
注意:想要這個(gè)方法生效驱闷,必須還要配合一個(gè)Flag一起使用,必須設(shè)置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
,并且不能設(shè)置FLAG_TRANSLUCENT_STATUS
(Android 4.4才用這個(gè))
ps:如果繪制的時(shí)候不清除這個(gè)flag或者加進(jìn)去空免,View.SYSTEM_UI_FLAG_LAYOUT_STABLE的話空另,實(shí)現(xiàn)statusBar繪制了同時(shí),自己的View也會(huì)入侵
這個(gè)flag 也是在Android 5.0添加的蹋砚,它的作用是什么呢扼菠?
解釋?zhuān)涸O(shè)置了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,表明會(huì)Window負(fù)責(zé)系統(tǒng)bar的background 繪制,繪制透明背景的系統(tǒng)bar(狀態(tài)欄和導(dǎo)航欄)坝咐,然后用getStatusBarColor()和getNavigationBarColor()的顏色填充相應(yīng)的區(qū)域循榆。這就是Android 5.0 以上實(shí)現(xiàn)沉浸式導(dǎo)航欄的原理。
實(shí)現(xiàn)沉浸式添加如下代碼:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//注意要清除 FLAG_TRANSLUCENT_STATUS flag
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(getResources().getColor(android.R.color.holo_red_light));
Android 5.0圖片延伸到狀態(tài)欄只需設(shè)置windowTranslucentStatus,將 statusBarColor 設(shè)置為透明即可:就是相當(dāng)于沒(méi)有清除FLAG_TRANSLUCENT_STATUS畅厢,所以xml入侵了
<style name="ImageTranslucentTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowTranslucentStatus">true</item>
<!-- 設(shè)置statusBarColor 為透明-->
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
tip
在Android 5.0 之后我們除了可以在代碼中改變狀態(tài)欄的顏色冯痢,還可以在XML中設(shè)置主題色,這種方式我們的App不屬于沉浸式框杜,在狀態(tài)欄的下面
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item> <!-- toolbar -->
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <!-- 狀態(tài)欄 -->
<item name="colorAccent">@color/colorAccent</item> <!-- 頁(yè)面中常用控件默認(rèn)顏色 -->
<item name="android:windowBackground">@color/bg_f6</item><!--window背景-->
</style>
注意:FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,表明會(huì)Window負(fù)責(zé)系統(tǒng)bar的background 繪制(得先清除4.4的flag)浦楣,所以不需要設(shè)置fitsSystemWindows或者手動(dòng)設(shè)置一個(gè)和statusBar一樣的大小的View,但是想實(shí)現(xiàn)圖片沉浸式咪辱,要設(shè)置windowTranslucentStatus
2.3 Android 6.0 + 實(shí)現(xiàn)狀態(tài)欄字色和圖標(biāo)淺黑色
使用沉浸式的時(shí)候會(huì)遇到一個(gè)問(wèn)題振劳,那就是Android 系統(tǒng)狀態(tài)欄的字色和圖標(biāo)顏色為白色,當(dāng)我的主題色或者圖片接近白色或者為淺色的時(shí)候油狂,狀態(tài)欄上的內(nèi)容就看不清了历恐。 ,這個(gè)問(wèn)題在Android 6.0的時(shí)候得到了解決专筷。Android 6.0 新添加了一個(gè)屬性SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
解釋?zhuān)簽閟etSystemUiVisibility(int)方法添加的Flag,請(qǐng)求status bar 繪制模式弱贼,它可以兼容亮色背景的status bar 。要在設(shè)置了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag ,同時(shí)清除了FLAG_TRANSLUCENT_STATUS flag 才會(huì)生效磷蛹。
代碼:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
除了在代碼中添加以外吮旅,還可以直接在主題中使用屬性:
<style name="MDTheme" parent="Theme.Design.Light.NoActionBar">
//為了防止沖突取消4.4的透明
<item name="android:windowTranslucentStatus">false</item>
//設(shè)置5.0的沉浸式
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
// 設(shè)置沉浸式煙色
<item name="android:statusBarColor">@android:color/holo_red_light</item>
<!-- Android 6.0以上 狀態(tài)欄字色和圖標(biāo)為淺黑色-->
<item name="android:windowLightStatusBar">true</item>
<!-- <item name="android:windowTranslucentStatus">true</item> --> <!-- 適用4.4到5.0的系統(tǒng)-->
</style>
好了說(shuō)到這里:如何統(tǒng)一4.4和5.0的沉浸式呢?
個(gè)人認(rèn)為方法有幾個(gè)方法:
法一:設(shè)置 fitsSystemWindows 屬性
這樣既能解決標(biāo)題欄入侵狀態(tài)欄問(wèn)題味咳,和輸入法彈出問(wèn)題
在 style theme 添加庇勃,或者Activity的layout的屬性android:fitsSystemWindows="true"!
屬性解釋?zhuān)涸诔两降那闆r下,如果某個(gè)View 的fitsSystemWindows 設(shè)為true槽驶,那么該View的padding屬性將由系統(tǒng)設(shè)置责嚷,用戶在布局文件中設(shè)置的padding會(huì)被忽略。系統(tǒng)會(huì)為該View設(shè)置一個(gè)paddingTop掂铐,值為statusbar的高度罕拂。fitsSystemWindows默認(rèn)為false
參考:http://www.reibang.com/p/5cc3bd23be7b
設(shè)置前這個(gè)屬性之前是這樣的的:
但是設(shè)置完之后就變成揍异,頂部變白色(其實(shí)那是根布局的顏色)
解決方法一:根布局設(shè)置為標(biāo)題所需要的顏色
解決方法二:自己在decoView繪制一個(gè)和狀態(tài)欄大小一樣,顏色和標(biāo)題欄一樣的View聂受!具體步驟!
解決:自己添加一個(gè)帶顏色和狀態(tài)欄一樣高的矩形的View
/**
* 生成一個(gè)和狀態(tài)欄大小相同的矩形條
*
* @param activity 需要設(shè)置的activity
* @param color 狀態(tài)欄顏色值
* @return 狀態(tài)欄矩形條
*/
private static View createStatusView(Activity activity, int color) {
// 獲得狀態(tài)欄高度
int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
int statusBarHeight = activity.getResources().getDimensionPixelSize(resourceId);
// 繪制一個(gè)和狀態(tài)欄一樣高的矩形
View statusView = new View(activity);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
statusBarHeight);
statusView.setLayoutParams(params);
statusView.setBackgroundColor(color);
return statusView;
}
整體代碼:
/**
* 設(shè)置狀態(tài)欄顏色
*
* @param activity 需要設(shè)置的activity
* @param color 狀態(tài)欄顏色值
*/
public static void setColor(Activity activity, int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// 設(shè)置狀態(tài)欄透明
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// 生成一個(gè)狀態(tài)欄大小的矩形
View statusView = createStatusView(activity, color);
// 添加 statusView 到布局中
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
decorView.addView(statusView);
// 設(shè)置根布局的參數(shù)
ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
rootView.setFitsSystemWindows(true);
rootView.setClipToPadding(true);
}
}
在 setContentView() 之后調(diào)用 setColor(Activity activity, int color) 方法即可蒿秦。
法二:設(shè)置手動(dòng)設(shè)置標(biāo)題欄的paddingTop
這可以實(shí)現(xiàn)titlebar整體文字不入侵狀態(tài)欄烤镐,ImageView整體浸入入侵狀態(tài)欄蛋济,但是得手動(dòng)解決輸入法問(wèn)題(5.0以后的不要清除FLAG_TRANSLUCENT_STATUS )
/**
* 通過(guò)設(shè)置全屏,設(shè)置狀態(tài)欄透明
*
* @param activity
*/
private void fullScreen(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//5.x開(kāi)始需要把顏色設(shè)置透明炮叶,否則導(dǎo)航欄會(huì)呈現(xiàn)系統(tǒng)默認(rèn)的淺灰色
Window window = activity.getWindow();
View decorView = window.getDecorView();
//兩個(gè) flag 要結(jié)合使用碗旅,表示讓?xiě)?yīng)用的主體內(nèi)容占用系統(tǒng)狀態(tài)欄的空間
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
//導(dǎo)航欄顏色也可以正常設(shè)置
// window.setNavigationBarColor(Color.TRANSPARENT);
} else {
Window window = activity.getWindow();
WindowManager.LayoutParams attributes = window.getAttributes();
int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
attributes.flags |= flagTranslucentStatus;
// attributes.flags |= flagTranslucentNavigation;
window.setAttributes(attributes);
}
}
}
public void setTitleBarPadding(final Activity activity, final View viewPadding) {
if (viewPadding != null) {
Object haveSetOffset = viewPadding.getTag(TAG_KEY_HAVE_SET_OFFSET);
if (haveSetOffset != null && (Boolean) haveSetOffset) {
return;
}
viewPadding.setPadding(viewPadding.getPaddingLeft(), viewPadding.getPaddingTop() + getStatusBarHeight(activity),
viewPadding.getPaddingRight(), viewPadding.getPaddingBottom());
viewPadding.setTag(TAG_KEY_HAVE_SET_OFFSET, true);
}
}
在 setContentView() 之后調(diào)用 fullScreen() 和setTitleBarPadding()方法即可。
法三:直接在標(biāo)題欄里面設(shè)置一個(gè)跟狀態(tài)欄一樣大小的View镜悉。
得到的效果與2類(lèi)似祟辟。
解決輸入法與沉浸式?jīng)_突:https://blog.csdn.net/smileiam/article/details/69055963
推薦庫(kù):https://github.com/gyf-dev/ImmersionBar
推薦工具類(lèi):https://github.com/laobie/StatusBarUtil