我們都知道檬嘀,安卓可以自定義狀態(tài)欄是從 API19(4.4) 開始的憾股,Google 給 KitKat 引入了 translucentStatusBar
特性英遭。從此掷伙,安卓也可以像 iOS 一樣自定義狀態(tài)欄的顏色务唐,甚至可以將布局布到狀態(tài)欄后面雳攘。然而,一如往常谷歌出的東西都是坑的尿性枫笛,谷歌卻沒考慮到將狀態(tài)欄設置為淺色后吨灭,狀態(tài)欄上的文字和圖標辨識困難的問題。(這不叫黑刑巧,這叫愛的深沉)
直到 Google 在 2015 年的 Google I/O 大會上推出了一個安卓狀態(tài)欄的新特性:LightStatusBarWindow
喧兄,即所謂的淺色狀態(tài)欄模式。從 API19 到 API23 過了整整四個大版本啊楚,這才解決了這個問題吠冤。沒錯,重要的東西總是晚來一步恭理。
然而拯辙,早在谷歌之前,國內的魅族與小米早已在自家的 Rom 中添加了淺色狀態(tài)欄的功能颜价。最低甚至支持 4.4 涯保。但是很多安卓開發(fā)者并不知道此事,以至于很多 app 使用了淺色的狀態(tài)欄導致用戶無法看清狀態(tài)欄上的文字圖標周伦。
MIUI茄猫、Flyme以及原生安卓的淺色狀態(tài)欄實現各不相同。而且這三個實現該功能的最低版本要求也不同困肩。MIUI 的要求為 MIUI V6 及以上划纽,Flyme 為 Flyme4 及以上,原生安卓為 API23 及以上锌畸∮铝樱考慮到國內 MIUI 及 Flyme 用戶的數量,所以我們的 app 中勢必需要對當前手機系統(tǒng)進行判斷之后調用合適的方法來設置淺色狀態(tài)欄潭枣。
以下是我總結的判斷手機系統(tǒng)淺色狀態(tài)欄是否可用的工具類:
public class RomUtils {
class AvailableRomType {
public static final int MIUI = 1;
public static final int FLYME = 2;
public static final int ANDROID_NATIVE = 3;
public static final int NA = 4;
}
public static boolean isLightStatusBarAvailable () {
if (isMIUIV6OrAbove() || isFlymeV4OrAbove() || isAndroidMOrAbove()) {
return true;
}
return false;
}
public static int getLightStatausBarAvailableRomType() {
if (isMIUIV6OrAbove()) {
return AvailableRomType.MIUI;
}
if (isFlymeV4OrAbove()) {
return AvailableRomType.FLYME;
}
if (isAndroidMOrAbove()) {
return AvailableRomType.ANDROID_NATIVE;
}
return AvailableRomType.NA;
}
//Flyme V4的displayId格式為 [Flyme OS 4.x.x.xA]
//Flyme V5的displayId格式為 [Flyme 5.x.x.x beta]
private static boolean isFlymeV4OrAbove() {
String displayId = Build.DISPLAY;
if (!TextUtils.isEmpty(displayId) && displayId.contains("Flyme")) {
String[] displayIdArray = displayId.split(" ");
for (String temp : displayIdArray) {
//版本號4以上比默,形如4.x.
if (temp.matches("^[4-9]\\.(\\d+\\.)+\\S*")) {
return true;
}
}
}
return false;
}
//MIUI V6對應的versionCode是4
//MIUI V7對應的versionCode是5
private static boolean isMIUIV6OrAbove() {
String miuiVersionCodeStr = getSystemProperty("ro.miui.ui.version.code");
if (!TextUtils.isEmpty(miuiVersionCodeStr)) {
try {
int miuiVersionCode = Integer.parseInt(miuiVersionCodeStr);
if (miuiVersionCode >= 4) {
return true;
}
} catch (Exception e) {}
}
return false;
}
//Android Api 23以上
private static boolean isAndroidMOrAbove() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return true;
}
return false;
}
private static String getSystemProperty(String propName) {
String line;
BufferedReader input = null;
try {
Process p = Runtime.getRuntime().exec("getprop " + propName);
input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
line = input.readLine();
input.close();
} catch (IOException ex) {
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
}
}
}
return line;
}
}
當判斷當前系統(tǒng)可以使用淺色狀態(tài)欄可以用后,根據得到的 Rom 類型調用對應的設置淺色狀態(tài)欄方法:
public class LightStatusBarUtils {
public static void setLightStatusBar(Activity activity, boolean dark) {
switch (RomUtils.getLightStatausBarAvailableRomType()) {
case RomUtils.AvailableRomType.MIUI:
setMIUILightStatusBar(activity, dark);
break;
case RomUtils.AvailableRomType.FLYME:
setFlymeLightStatusBar(activity, dark);
break;
case RomUtils.AvailableRomType.ANDROID_NATIVE:
setAndroidNativeLightStatusBar(activity, dark);
break;
case RomUtils.AvailableRomType.NA:
// N/A do nothing
break;
}
}
private static boolean setMIUILightStatusBar(Activity activity, boolean darkmode) {
Class<? extends Window> clazz = activity.getWindow().getClass();
try {
int darkModeFlag = 0;
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private static boolean setFlymeLightStatusBar(Activity activity, boolean dark) {
boolean result = false;
if (activity != null) {
try {
WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
Field darkFlag = WindowManager.LayoutParams.class
.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class
.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
if (dark) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(lp, value);
activity.getWindow().setAttributes(lp);
result = true;
} catch (Exception e) {
}
}
return result;
}
private static void setAndroidNativeLightStatusBar(Activity activity, boolean dark) {
View decor = activity.getWindow().getDecorView();
if (dark) {
decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
// We want to change tint color to white again.
// You can also record the flags in advance so that you can turn UI back completely if
// you have set other flags before, such as translucent or full screen.
decor.setSystemUiVisibility(0);
}
}
}
以上就是我總結的用于設置淺色狀態(tài)欄的兩個主要類:RomUtils 用于判定當前系統(tǒng)是否可用淺色狀態(tài)欄模式盆犁,以及當前系統(tǒng)的類型命咐。LightStatusBarUtils 包含了各個系統(tǒng)對應的設置淺色狀態(tài)欄的方法,開發(fā)者可以根據 RomUtils 得到的 Rom 類型調用其中對應的方法谐岁。
接著我們創(chuàng)建一個 app 項目醋奠,來試試效果。在 MainActivity 的布局中我放了兩個 TextView 和一個 Button伊佃。兩個 TextView 分別用于顯示當前系統(tǒng)版本信息和顯示當前系統(tǒng)是否可用淺色狀態(tài)欄模式窜司。Button 用于在淺色狀態(tài)欄模式和普通模式之間切換。
以下是 MainActivity :
public class MainActivity extends AppCompatActivity {
private boolean isLightStatusBarNow = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView sysInfoTv = (TextView) findViewById(R.id.tv_sys_info);
TextView hintTv = (TextView) findViewById(R.id.tv_hint);
Button switchBtn = (Button) findViewById(R.id.btn_switch);
sysInfoTv.setText(Build.BRAND + " - " + Build.MODEL + " - SDK Version:" + Build.VERSION.SDK_INT);
switch (RomUtils.getLightStatausBarAvailableRomType()) {
case RomUtils.AvailableRomType.MIUI:
hintTv.setText("當前系統(tǒng)為MIUI6或以上 淺色狀態(tài)欄可用");
break;
case RomUtils.AvailableRomType.FLYME:
hintTv.setText("當前系統(tǒng)為Flyme4或以上 淺色狀態(tài)欄可用");
break;
case RomUtils.AvailableRomType.ANDROID_NATIVE:
hintTv.setText("當前系統(tǒng)為Android M或以上 淺色狀態(tài)欄可用");
break;
case RomUtils.AvailableRomType.NA:
hintTv.setText("當前系統(tǒng)淺色狀態(tài)欄不可用");
switchBtn.setEnabled(false);
switchBtn.setText("light status bar mode not available");
break;
}
switchBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isLightStatusBarNow) {
LightStatusBarUtils.setLightStatusBar(MainActivity.this, false);
isLightStatusBarNow = false;
} else {
LightStatusBarUtils.setLightStatusBar(MainActivity.this, true);
isLightStatusBarNow = true;
}
}
});
}
}
手機上運行效果:
一些常見機型上的效果:
存在的坑:
- 使用原生安卓的方法來實現淺色狀態(tài)欄的前提是航揉,當前 Activity 所在的 Window 必須有
windowDrawsSystemBarBackgrounds
屬性塞祈,而且必須未設置過windowTranslucentStatus
屬性。
如果當前 Window 設置了windowTranslucentStatus
屬性帅涂,那么調用上面設置淺色狀態(tài)欄的方法就不會生效议薪。
詳細見 API 說明:
https://developer.android.com/reference/android/R.attr.html#windowLightStatusBar - 據說安卓原生實現方法在 MIUI android 版本為6.0上無效(見參考2,手頭沒設備測試)媳友。所以我的代碼中將 MIUI 和 Flyme 的判斷放在原生安卓前面笙蒙,這樣如果是 MIUI 或 Flyme 的設備,優(yōu)先調用各自的實現方法庆锦。
Demo代碼: 地址
參考:
- http://blog.isming.me/2016/01/09/chang-android-statusbar-text-color/
- http://www.reibang.com/p/7f5a9969be53
- http://dev.xiaomi.com/doc/?p=254
- http://blog.csdn.net/devilkin64/article/details/19415717
本文章為原創(chuàng)作品,轉載請注明出處轧葛。