詳解Android沉浸式實現相容解決辦法

詳解Android沉浸式實現相容解決辦法

自android5.0開始,沉浸式狀態列似乎成為一種潮流,應用裡缺少沉浸式總感覺少些什麼。於是乎,我開始到處找如何相容低版本的沉浸式,由於Android平臺跨度問題,總遇到一些不如人意的問題。終於,皇天不負有心人,通過參考一些網路上的資料以及開發的一些經驗,總結出一個可行的且良好的解決方案!

先介紹下,什麼是沉浸式狀態列?

沉浸式,要求在應用中Android狀態列(StatusBar)與標題欄(ActionBar/Toolbar)要擁有相同的顏色,或者使用同一張圖的連續背景。

話不多說,亮劍吧!

具體實現需要針對不同Android版本做處理,還有針對DecorView做處理以及做activity的xml佈局檔案根佈局控制元件做屬性處理。

java程式碼,設定沉浸式的方法


/**
* 設定沉浸式狀態列顏色
*
* @param colorResId 狀態列顏色
*/
protected void setImmersiveStatusBarColor(@ColorRes int colorResId) {
int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
int statusBarColor = ApkUtil.getColor(this, colorResId); //①
float lightDegress = (Color.red(statusBarColor)   Color.green(statusBarColor)   Color.blue(statusBarColor)) / 3; //作色彩亮度判斷,好針對顏色做相應的狀態列的暗色還是亮色。
if ((lightDegress > 200 || lightDegress == 0) && Build.VERSION.SDK_INT > Build.VERSION_CODES.M)
rootView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.setStatusBarColor(statusBarColor);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
rootView.setSystemUiVisibility(flags | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
rootView.setSystemUiVisibility(flags);
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { //當API小於等於19,此時為了實現沉浸式狀態列,需要新增一個view來做statusbar背景控制元件
final boolean isHasStatusBarView = rootView.getTag() != null;
View statusbarView = !isHasStatusBarView ? new View(this) : (View)rootView.getTag();
statusbarView.setBackgroundResource(colorResId);
if(!isHasStatusBarView) {
rootView.setTag(statusBarView);
statusbarView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, ViewUtil.getStatusBarHeight(this))); //②
rootView.addView(statusbarView);
}
}
}

注:此處針對rootView(即DecorView)、window的獲取不再陳述!

①.ApkUtil.getColor(this, colorResId)


/**
* 獲取顏色資源
* @param context 上下文物件
* @param colorId 顏色ResId
* @return
*/
@SuppressWarnings("deprecation")
public static int getColor(Context context, int colorId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return context.getColor(colorId);
}
return context.getResources().getColor(colorId);
}

②. 獲取狀態列高度


/**
* 獲取狀態列高度
* @param context 上下文物件
*/
@JvmStatic
@SuppressLint("PrivateApi")
fun getStatusBarHeight(context: Context): Int {
val clazz = Class.forName("com.android.internal.R\$dimen")
val obj = clazz?.newInstance()
val field = clazz.getField("status_bar_height")
field?.let {
field.isAccessible = true
val x = Integer.parseInt(field.get(obj).toString())
return context.resources.getDimensionPixelSize(x)
}
return 75
}

activity佈局xml根佈局新增以下屬性


android:fitsSystemWindows="true"
android:clipToPadding="false"