這里推薦一下鴻洋大神寫的一篇博客Android 沉浸式狀態欄攻略 讓你的狀態欄變色吧,文章中寫的很詳細,可以作為參考,因此這里只是簡單講述下設置沉浸式狀態欄的步驟,主要是說一下我在使用過程中碰到的一些問題以及解決方法。
設置沉浸式狀態欄
- 如果看過上面推薦的博客就會知道,設置沉浸式狀態欄通常分為3個步驟(缺一不可)
- 在styles文件中添加
<item name="android:windowTranslucentStatus">true</item>
, - Toolbar布局文件中設置高度為
android:layout_height="wrap_content"
, - Toolbar布局添加
android:fitsSystemWindows="true"
屬性(注意:如果ToolBar外層還包裹了AppBarLayout布局,則需要將android:fitsSystemWindows="true"
屬性設置在AppBarLayout布局中。另外如果設置了側滑菜單,要將菜單布局也延伸到狀態欄中的話,同樣需要在菜單布局文件的根布局中設置android:fitsSystemWindows屬性)。
遇到的問題
-
界面中有EditText組件,當EditText獲取焦點彈出軟鍵盤時,ToolBar的布局會延伸,如下圖所示:
image.png 當有登錄界面并且登錄界面輸入框較多彈出的軟鍵盤將下面的輸入框擋住時,即使將這些輸入框用ScrollView包裹并且在manifest.xml文件中設置了
android:windowSoftInputMode="adjustResize|stateHidden"
時,會有一部分布局依然是被軟鍵盤擋住,無法滑動上來)。-
在開發中我們通常會遇到實現一些信息錄入的功能,界面布局通常也是最上面是ToolBar,最下面是一個保存按鈕(有時也會添加一個取消按鈕,也有可能是一個Tab組件),中間則是多個信息輸入框,一般情況下我是比較希望當輸入框獲取焦點彈出軟鍵盤的時候,底部的按鈕一同被頂上來,比如說像下圖這樣(中間的輸入框是用ScrollView包裹起來的)
image.png
而實際情況是,當我們按照上面設置的步驟只要在styles文件中設置了
<item name="android:windowTranslucentStatus">true</item>
這個屬性就會發現當輸入組件獲取焦點軟件盤彈出時,底部的按鈕是不會被頂上來的,這個就有點坑爹了。雖然沒什么大的影響,但作為有強迫癥的我是不允許出現這種情況的。
- 好了基本上我在使用沉浸式狀態欄過程中碰到的一些問題都列在上面了,可能還有別的問題沒有碰到,這個以后再說。
問題原因及解決方法
這里參考了一篇博客談談“adjustResize”在沉浸式狀態欄下的失效問題,該博客完美的解決了上面所說的問題,我就直接將其中的一些內容照抄過來了。
問題原因
- 其實大部分問題都是由
android:fitsSystemWindows="true"
和<item name="android:windowTranslucentStatus">true</item>
這兩個屬性引起的,因此對應的解決方案主要是針對他們的。
- 上面的第一個問題也就是輸入框獲取焦點軟鍵盤彈出時ToolBar布局出現延伸的問題,這個問題是由于對ToolBar布局設置了
android:fitsSystemWindows="true"
。 - 上面的第二個和第三個問題是因為我們在styles文件中設置了
<item name="android:windowTranslucentStatus">true</item>
這個屬性引起的。我在使用的時候發現只要設置了這個屬性,界面布局簡短的時候還好,當界面布局比較長以以至于有一部分被彈出的軟件盤遮住的時候,不管我使用什么辦法,都無法將被遮住的布局滑上來(貌似使用列表組件可以,但是我沒試過,而且列表組件限制比較大,比如說界面輸入是用Fragment實現的)。
解決方法
- 最佳的解決方法就是不用沉浸式,畢竟現在手機都是5.0以上的,可以直接設置狀態欄的藍色,我們可以直接在項目中設置最低版本為api21版本。
- 針對ToolBar布局延伸,參照上面引用博客,我們自定義布局,將ToolBar包裹進去,并將
android:fitsSystemWindows="true"
屬性設置在自定義的布局里面,同時ToolBar的背景顏色也到移動到自定的布局里面,否則狀態欄不會顯示我們設置好的顏色,代碼如下:
<com.mobile.library.view.ImmerseGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="@+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?actionBarSize"
app:popupTheme="@style/PopupOverlay"
app:theme="@style/AppBarOverlay">
</android.support.v7.widget.Toolbar>
</com.mobile.library.view.ImmerseGroup>
該自定義布局代碼如下:
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* 沉浸式狀態欄Toolbar輔助類
* 避免Toolbar設置fitSystemWindows="true"當軟鍵盤彈出時Toolbar被拉伸
*/
public class ImmerseGroup extends FrameLayout {
public ImmerseGroup(Context context) {
super(context);
}
public ImmerseGroup(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public ImmerseGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), 0);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
- 這樣便解決了ToolBar布局延伸的問題,但是另外一個問題還沒有解決,就是底部的組件如何才能被軟鍵盤頂上來,這里采用了一個工具類來監聽android.R.id.content的布局,在軟鍵盤彈出時,動態改變其高度,為軟鍵盤騰出空間。該工具類代碼如下:
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
public class AndroidBug5497Workaround {
public static void assistActivity(View content) {
new AndroidBug5497Workaround(content);
}
private View mChildOfContent;
private int usableHeightPrevious;
private ViewGroup.LayoutParams frameLayoutParams;
private AndroidBug5497Workaround(View content) {
if (content != null) {
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);
}
}
然后在需要設置的Activity中添加下面一行代碼就可以了:
AndroidBug5497Workaround.assistActivity(findViewById(android.R.id.content));
題外話
- 有時候我們嫌沉浸式布局比較麻煩,不想使用,但又想在5.0以下的手機上設置狀態欄的顏色,這里安利一個GitHub上面的開源庫msdx/status-bar-compat,其實現的狀態欄效果和沉浸式狀態欄幾乎一樣(布局并沒有延伸到狀態欄上面),我已經用在了自己的項目上面,在此感謝該開源庫作者的辛勤維護。