Android從4.4開始有沉浸式狀態欄效果,5.0以前的實現很簡單:
如果手機版本大於等於4.4,就實現沉浸式狀態欄效果:
//4.4版本及以上 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { window.setFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); }但是5.0及其以上的,還是有個小藍條在最上面,沒有達到沉浸式狀態欄效果,對於5.0及其以上系統的解決辦法:
//5.0版本及以上 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); window.setNavigationBarColor(Color.BLACK); }
綜上,可以寫個基類,讓其他activity繼承此基類即可:
public class BaseActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); immersiveStatusBar(); } private void immersiveStatusBar() { Window window = getWindow(); //4.4版本及以上 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { window.setFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } //5.0版本及以上 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); window.setNavigationBarColor(Color.BLACK); } if (AndroidWorkaround.checkDeviceHasNavigationBar(this)) { AndroidWorkaround.assistActivity(findViewById(android.R.id.content)); } } }
這樣,所有系統均可適配沉浸式狀態欄了。
注:使用沉浸式狀態欄後,有的華爲手機下面的虛擬按鍵會把項目的底部導航(如果有的話)給遮蓋,解決辦法:
一、概述
在項目中,測試發現在一些華爲手機的屏幕適配上出現了問題,主要是因爲華爲Mate等一些系列的手機有一個虛擬按鍵的設計.當這些虛擬按鍵由用戶手勢滑出,或默認顯示的話,就會遮擋我們本身的應用佈局.比如歡迎界面過後是四個Fragment,那麼底部的四個tab就會被虛擬的導航欄遮住,非常難看.
當然,歡迎頁的圖片適配也同樣會出現問題.
Google後得出第一個問題的解決方案.第二個圖片的問題則用自己摸索的方式解決,當然也非常簡單.
二、佈局由於虛擬按鍵導致導航欄頂上去的解決方法
在我們的項目中加載Fragment的MainActivity,以及其他一般的Activity繼承的BaseActivity中的onCreate方法中添加如下代碼:
if (AndroidWorkaround.checkDeviceHasNavigationBar(this)) {
AndroidWorkaround.assistActivity(findViewById(android.R.id.content));
}
其中AndroidWorkaround使我們爲了解決該問題而封裝的類,也可以看作是一個特定的工具類:
/**
* 解決底部屏幕按鍵適配
* Created by Mercury on 2016/10/25.
*/
public class AndroidWorkaround {
public static void assistActivity(View content) {
new AndroidWorkaround(content);
}
private View mChildOfContent;
private int usableHeightPrevious;
private ViewGroup.LayoutParams frameLayoutParams;
private AndroidWorkaround(View content) {
mChildOfContent = content;
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
possiblyResizeChildOfContent();
}
});
frameLayoutParams = mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious) {
frameLayoutParams.height = usableHeightNow;
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom);
}
public static boolean checkDeviceHasNavigationBar(Context context) {
boolean hasNavigationBar = false;
Resources rs = context.getResources();
int id = rs.getIdentifier("config_showNavigationBar", "bool", "android");
if (id > 0) {
hasNavigationBar = rs.getBoolean(id);
}
try {
Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
Method m = systemPropertiesClass.getMethod("get", String.class);
String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
if ("1".equals(navBarOverride)) {
hasNavigationBar = false;
} else if ("0".equals(navBarOverride)) {
hasNavigationBar = true;
}
} catch (Exception e) {
}
return hasNavigationBar;
}
}
重新測試,發現無論是否彈出虛擬按鍵,都不會再次遮擋tab按鈕。
三、原理
上面的代碼需要在setContentView後面執行。其最初的解決方案是stackoverflow上有人爲了適配軟鍵盤在全屏下的佈局問題。
開始先判斷該設備上是否存在導航欄。爲什麼用findViewById(Android.R.id.content)呢?因爲android.R.id.content這個id代表的就是所在頁面的根佈局,而並不需要特別指定一個id給該佈局。可以通過調用系統API返回的結果,也可以通過判斷該手機是否爲華爲手機,操作系統屬於哪種類型來來判斷。
一旦確定該設備存在導航欄,將對該佈局進行重新測量。首先mChildOfContent得到其視圖樹,對全局高度實現監聽。
OnGlobalLayoutListener 是ViewTreeObserver的內部類,當一個視圖樹的佈局發生改變時,可以被ViewTreeObserver監聽到,這是一個註冊監聽視圖樹的觀察者(observer),在視圖樹的全局事件改變時得到通知。ViewTreeObserver不能直接實例化,而是通過getViewTreeObserver()獲得。
接着得到視圖目前可用的總高度,將其賦值給mChildOfContent的佈局高度。調用requestLayout,讓mChildOfContent要求自己的parent view對自己重新設置位置。
四、全屏圖片的適配
解決了佈局的問題,再來看歡迎頁啓動時候全屏圖片的適配問題。發現該方法對於圖片不適用。如下圖,當虛擬按鍵彈出時,圖片照樣被遮擋了底部的一小部分。
如果隱藏虛擬按鍵,圖片大小恢復正常
仔細想想,對於一個ImageView直接佔據一個layout的情況,是沒有必要再去寫一些代碼進行適配的。到佈局裏一看,發現ImageView的屬性 android:scaleType=”centerCrop”
將其改爲 android:scaleType=”fitXY”就可以解決了。這樣圖片可能高度會隨着虛擬鍵的彈出而壓縮,但是很好的適配了佈局高度的變化而不會被遮擋。