Android修改狀態欄顏色全方位教程
阿新 • • 發佈:2018-01-25
content android-m 控件 -c mst exc icon turn span
在Android 6.0的Api中提供了SYSTEM_UI_FLAG_LIGHT_STATUS_BAR這麽一個常量,可以使狀態欄文字設置為黑色,但對6.0以下是不起作用的。
小米和魅族的手機也可以達到這個效果,要做一些特殊的處理。可以參考小米和魅族的開發者文檔。
Flyme沈浸式狀態欄
MIUI 6 沈浸式狀態欄調用方法
MIUI 9「狀態欄黑色字符」實現方法變更通知
關鍵字:狀態欄著色 透明狀態欄 沈浸式 白底黑字
Github Demo:https://github.com/imflyn/Eyes
參考文章:
Android-transulcent-status-bar
Android 6.0狀態欄使用灰色文字和圖標
Android系統更改狀態欄字體顏色
在谷歌官方的material設計文檔中定義了新的狀態欄設計。
https://material.io/guidelines/layout/structure.html#structure-system-bars
默認情況下,狀態欄的顏色是黑色的。同時狀態欄顏色也可以半透明或是指定任意一種顏色。
1.改變顏色後的狀態欄
2.半透明狀態欄
3.黑色狀態欄
黑色icon或文字的狀態欄
接下來講一下具體實現
一.改變狀態欄顏色
4.4-5.0的處理:
4.4-5.0還沒有API可以直接修改狀態欄顏色,所以必須先將狀態欄設置為透明,然後在布局中添加一個背景為期望色值的View來作為狀態欄的填充。
static void setStatusBarColor(Activity activity, int statusColor) {
Window window = activity.getWindow();
//設置Window為全透明
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
//獲取父布局
View mContentChild = mContentView.getChildAt(0);
//獲取狀態欄高度
int statusBarHeight = getStatusBarHeight(activity);
//如果已經存在假狀態欄則移除,防止重復添加
removeFakeStatusBarViewIfExist(activity);
//添加一個View來作為狀態欄的填充
addFakeStatusBarView(activity, statusColor, statusBarHeight);
//設置子控件到狀態欄的間距
addMarginTopToContentChild(mContentChild, statusBarHeight);
//不預留系統欄位置
if (mContentChild != null) {
ViewCompat.setFitsSystemWindows(mContentChild, false);
}
//如果在Activity中使用了ActionBar則需要再將布局與狀態欄的高度跳高一個ActionBar的高度,否則內容會被ActionBar遮擋
int action_bar_id = activity.getResources().getIdentifier("action_bar", "id", activity.getPackageName());
View view = activity.findViewById(action_bar_id);
if (view != null) {
TypedValue typedValue = new TypedValue();
if (activity.getTheme().resolveAttribute(R.attr.actionBarSize, typedValue, true)) {
int actionBarHeight = TypedValue.complexToDimensionPixelSize(typedValue.data, activity.getResources().getDisplayMetrics());
setContentTopPadding(activity, actionBarHeight);
}
}
}
private static void removeFakeStatusBarViewIfExist(Activity activity) {
Window window = activity.getWindow();
ViewGroup mDecorView = (ViewGroup) window.getDecorView();
View fakeView = mDecorView.findViewWithTag(TAG_FAKE_STATUS_BAR_VIEW);
if (fakeView != null) {
mDecorView.removeView(fakeView);
}
}
private static View addFakeStatusBarView(Activity activity, int statusBarColor, int statusBarHeight) {
Window window = activity.getWindow();
ViewGroup mDecorView = (ViewGroup) window.getDecorView();
View mStatusBarView = new View(activity);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);
layoutParams.gravity = Gravity.TOP;
mStatusBarView.setLayoutParams(layoutParams);
mStatusBarView.setBackgroundColor(statusBarColor);
mStatusBarView.setTag(TAG_FAKE_STATUS_BAR_VIEW);
mDecorView.addView(mStatusBarView);
return mStatusBarView;
}
private static void addMarginTopToContentChild(View mContentChild, int statusBarHeight) {
if (mContentChild == null) {
return;
}
if (!TAG_MARGIN_ADDED.equals(mContentChild.getTag())) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentChild.getLayoutParams();
lp.topMargin += statusBarHeight;
mContentChild.setLayoutParams(lp);
mContentChild.setTag(TAG_MARGIN_ADDED);
}
}
static void setContentTopPadding(Activity activity, int padding) {
ViewGroup mContentView = (ViewGroup) activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT);
mContentView.setPadding(0, padding, 0, 0);
}
Android5.0以上的處理:
static void setStatusBarColor(Activity activity, int statusColor) {
Window window = activity.getWindow();
//取消狀態欄透明
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//添加Flag把狀態欄設為可繪制模式
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//設置狀態欄顏色
window.setStatusBarColor(statusColor);
//設置系統狀態欄處於可見狀態
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
//讓view不根據系統窗口來調整自己的布局
ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
View mChildView = mContentView.getChildAt(0);
if (mChildView != null) {
ViewCompat.setFitsSystemWindows(mChildView, false);
ViewCompat.requestApplyInsets(mChildView);
}
}
二.透明狀態欄
4.4-5.0的處理:
static void translucentStatusBar(Activity activity) {
Window window = activity.getWindow();
//設置Window為透明
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
View mContentChild = mContentView.getChildAt(0);
//移除已經存在假狀態欄則,並且取消它的Margin間距
removeFakeStatusBarViewIfExist(activity);
removeMarginTopOfContentChild(mContentChild, getStatusBarHeight(activity));
if (mContentChild != null) {
//fitsSystemWindow 為 false, 不預留系統欄位置.
ViewCompat.setFitsSystemWindows(mContentChild, false);
}
}
5.0以上的處理:
static void translucentStatusBar(Activity activity, boolean hideStatusBarBackground) {
Window window = activity.getWindow();
//添加Flag把狀態欄設為可繪制模式
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
if (hideStatusBarBackground) {
//如果為全透明模式,取消設置Window半透明的Flag
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//設置狀態欄為透明
window.setStatusBarColor(Color.TRANSPARENT);
//設置window的狀態欄不可見
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
} else {
//如果為半透明模式,添加設置Window半透明的Flag
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//設置系統狀態欄處於可見狀態
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
//view不根據系統窗口來調整自己的布局
ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
View mChildView = mContentView.getChildAt(0);
if (mChildView != null) {
ViewCompat.setFitsSystemWindows(mChildView, false);
ViewCompat.requestApplyInsets(mChildView);
}
}
三.使用CollapsingToolbarLayout使ToolBar具有折疊效果
類似圖片中的效果
首先是XML布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="256dp"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="@color/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:statusBarScrim="@color/colorPrimary">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@drawable/timg"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="24dp">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dip">
<TextView
android:layout_width="match_parent"
android:layout_height="240dip"
android:text="A"
android:textAppearance="@style/TextAppearance.AppCompat.Title" />
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="240dip"
android:layout_margin="16dip">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="B"
android:textAppearance="@style/TextAppearance.AppCompat.Title" />
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dip">
<TextView
android:layout_width="match_parent"
android:layout_height="240dip"
android:text="C"
android:textAppearance="@style/TextAppearance.AppCompat.Title" />
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="240dip"
android:layout_margin="16dip">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="D"
android:textAppearance="@style/TextAppearance.AppCompat.Title" />
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
4.4-5.0的處理:
static void setStatusBarColorForCollapsingToolbar(Activity activity, final AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout,
Toolbar toolbar, int statusColor) {
Window window = activity.getWindow();
//設置Window為全透明
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
//AppBarLayout,CollapsingToolbarLayout,ToolBar,ImageView的fitsSystemWindow統一改為false, 不預留系統欄位置.
View mContentChild = mContentView.getChildAt(0);
mContentChild.setFitsSystemWindows(false);
((View) appBarLayout.getParent()).setFitsSystemWindows(false);
appBarLayout.setFitsSystemWindows(false);
collapsingToolbarLayout.setFitsSystemWindows(false);
collapsingToolbarLayout.getChildAt(0).setFitsSystemWindows(false);
toolbar.setFitsSystemWindows(false);
//為Toolbar添加一個狀態欄的高度, 同時為Toolbar添加paddingTop,使Toolbar覆蓋狀態欄,ToolBar的title可以正常顯示.
if (toolbar.getTag() == null) {
CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) toolbar.getLayoutParams();
int statusBarHeight = getStatusBarHeight(activity);
lp.height += statusBarHeight;
toolbar.setLayoutParams(lp);
toolbar.setPadding(toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom());
toolbar.setTag(true);
}
//移除已經存在假狀態欄則,並且取消它的Margin間距
int statusBarHeight = getStatusBarHeight(activity);
removeFakeStatusBarViewIfExist(activity);
removeMarginTopOfContentChild(mContentChild, statusBarHeight);
//添加一個View來作為狀態欄的填充
final View statusView = addFakeStatusBarView(activity, statusColor, statusBarHeight);
CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams()).getBehavior();
if (behavior != null && behavior instanceof AppBarLayout.Behavior) {
int verticalOffset = ((AppBarLayout.Behavior) behavior).getTopAndBottomOffset();
if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) {
statusView.setAlpha(1f);
} else {
statusView.setAlpha(0f);
}
} else {
statusView.setAlpha(0f);
}
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) {
//toolbar被折疊時顯示狀態欄
if (statusView.getAlpha() == 0) {
statusView.animate().cancel();
statusView.animate().alpha(1f).setDuration(collapsingToolbarLayout.getScrimAnimationDuration()).start();
}
} else {
//toolbar展開時顯示狀態欄
if (statusView.getAlpha() == 1) {
statusView.animate().cancel();
statusView.animate().alpha(0f).setDuration(collapsingToolbarLayout.getScrimAnimationDuration()).start();
}
}
}
});
}
5.0以上的處理:
static void setStatusBarColorForCollapsingToolbar(final Activity activity, final AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout,
Toolbar toolbar, final int statusColor) {
final Window window = activity.getWindow();
//取消設置Window半透明的Flag
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
////添加Flag把狀態欄設為可繪制模式
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//設置狀態欄為透明
window.setStatusBarColor(Color.TRANSPARENT);
//設置系統狀態欄處於可見狀態
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
//通過OnApplyWindowInsetsListener()使Layout在繪制過程中將View向下偏移了,使collapsingToolbarLayout可以占據狀態欄
ViewCompat.setOnApplyWindowInsetsListener(collapsingToolbarLayout, new OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
return insets;
}
});
ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
View mChildView = mContentView.getChildAt(0);
//view不根據系統窗口來調整自己的布局
if (mChildView != null) {
ViewCompat.setFitsSystemWindows(mChildView, false);
ViewCompat.requestApplyInsets(mChildView);
}
((View) appBarLayout.getParent()).setFitsSystemWindows(false);
appBarLayout.setFitsSystemWindows(false);
collapsingToolbarLayout.setFitsSystemWindows(false);
collapsingToolbarLayout.getChildAt(0).setFitsSystemWindows(false);
//設置狀態欄的顏色
collapsingToolbarLayout.setStatusBarScrimColor(statusColor);
toolbar.setFitsSystemWindows(false);
//為Toolbar添加一個狀態欄的高度, 同時為Toolbar添加paddingTop,使Toolbar覆蓋狀態欄,ToolBar的title可以正常顯示.
if (toolbar.getTag() == null) {
CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) toolbar.getLayoutParams();
int statusBarHeight = getStatusBarHeight(activity);
lp.height += statusBarHeight;
toolbar.setLayoutParams(lp);
toolbar.setPadding(toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom());
toolbar.setTag(true);
}
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
private final static int EXPANDED = 0;
private final static int COLLAPSED = 1;
private int appBarLayoutState;
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
//toolbar被折疊時顯示狀態欄
if (Math.abs(verticalOffset) > collapsingToolbarLayout.getScrimVisibleHeightTrigger()) {
if (appBarLayoutState != COLLAPSED) {
appBarLayoutState = COLLAPSED;//修改狀態標記為折疊
setStatusBarColor(activity, statusColor);
}
} else {
//toolbar顯示時同時顯示狀態欄
if (appBarLayoutState != EXPANDED) {
appBarLayoutState = EXPANDED;//修改狀態標記為展開
translucentStatusBar(activity, true);
}
}
}
});
}
四.更改狀態欄字體顏色
在Android 6.0的Api中提供了SYSTEM_UI_FLAG_LIGHT_STATUS_BAR這麽一個常量,可以使狀態欄文字設置為黑色,但對6.0以下是不起作用的。
小米和魅族的手機也可以達到這個效果,要做一些特殊的處理。可以參考小米和魅族的開發者文檔。
Flyme沈浸式狀態欄
MIUI 6 沈浸式狀態欄調用方法
MIUI 9「狀態欄黑色字符」實現方法變更通知
public static void setStatusBarLightMode(Activity activity, int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//判斷是否為小米或魅族手機,如果是則將狀態欄文字改為黑色
if (MIUISetStatusBarLightMode(activity, true) || FlymeSetStatusBarLightMode(activity, true)) {
//設置狀態欄為指定顏色
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0
activity.getWindow().setStatusBarColor(color);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//4.4
//調用修改狀態欄顏色的方法
setStatusBarColor(activity, color);
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//如果是6.0以上將狀態欄文字改為黑色,並設置狀態欄顏色
activity.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
activity.getWindow().setStatusBarColor(color);
//fitsSystemWindow 為 false, 不預留系統欄位置.
ViewGroup mContentView = (ViewGroup) activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT);
View mChildView = mContentView.getChildAt(0);
if (mChildView != null) {
ViewCompat.setFitsSystemWindows(mChildView, true);
ViewCompat.requestApplyInsets(mChildView);
}
}
}
}
小米MiUi修改狀態欄方法
static boolean MIUISetStatusBarLightMode(Activity activity, boolean darkmode) {
boolean result = false;
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);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
如果是MIUI9的系統還需要加上這段代碼
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
Flyme修改狀態欄方法
static boolean FlymeSetStatusBarLightMode(Activity activity, boolean darkmode) {
boolean result = false;
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 (darkmode) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(lp, value);
activity.getWindow().setAttributes(lp);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
結語:
更詳細的參考Demo在github中,如果有錯誤也希望大家能夠指出。
作者:imflyn
鏈接:https://www.jianshu.com/p/932568ed31af
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請註明出處。
Android修改狀態欄顏色全方位教程