前言
随着android版本的提升,android5.0之后支持能改动状态栏的颜色,或者是透明.
实现的方式无非就是Theme设置和代码设置。
API21 之后(android 5.0 之后)的状态栏,会默认覆盖一层半透明遮罩。且为了保持4.4以前系统正常使用,故需要三份 style 文件,即默认的values(不设置状态栏透明)、values-v19、values-v21(解决半透明遮罩问题)。
//valuse
<style name="TranslucentTheme" parent="AppTheme">
</style>
// values-v19。v19 开始有 android:windowTranslucentStatus 这个属性
<style name="TranslucentTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
// values-v21。5.0 以上提供了 setStatusBarColor() 方法设置状态栏颜色。
<style name="TranslucentTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">true</item>
<!--Android 5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色-->
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
效果可见
test3.png
由此可见有ActionBar主题下,布局的图片会延伸到状态栏中。但这样肯定是不行。所以我们需要在根布局添加android:fitsSystemWindows="true" 属性。就可以让图片不会显示在顶部栏。当然也可以代码设置,
/**
* 设置页面最外层布局 FitsSystemWindows 属性
* @param activity
* @param value
*/
public static void setFitsSystemWindows(Activity activity, boolean value) {
ViewGroup contentFrameLayout = (ViewGroup) activity.findViewById(android.R.id.content);
View parentView = contentFrameLayout.getChildAt(0);
if (parentView != null && Build.VERSION.SDK_INT >= 14) {
parentView.setFitsSystemWindows(value);
}
}
但这种方式实现有些问题,例如我们想设置状态栏为蓝色,只能通过设置最外层布局的背景为蓝色来实现,然而一旦设置后,整个布局就都变成了蓝色,只能在下方的布局内容里另外再设置白色背景,而这样就存在过度绘制了。而且设置了 fitsSystemWindows=true 属性的页面,在点击 EditText 调出 软键盘时,整个视图都会被顶上去。影响很大。
所以另一种方式就是在根据布局中再添加一个view来顶上状态栏的位置。补上空缺。当然也可以直接用代码的方式。
<View
android:id="@+id/statusBarView"
android:background="@color/blue"
android:layout_width="match_parent"
android:layout_height="wrap_content"></View>
public int getStatusBarHeight() {
int result = 0;
//获取状态栏高度的资源id
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
//为布局中的View设置状态栏高度
View statusBar = findViewById(R.id.statusBarView);
ViewGroup.LayoutParams layoutParams = statusBar.getLayoutParams();
layoutParams.height = getStatusBarHeight();
代码方式:
/**
* 添加状态栏占位视图
*
* @param activity
*/
private void addStatusViewWithColor(Activity activity, int color) {
ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
View statusBarView = new View(activity);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
getStatusBarHeight(activity));
statusBarView.setBackgroundColor(color);
contentView.addView(statusBarView, lp);
}
不过还有种较好的方式就是,手动给根视图设置一个 paddingTop ,高度为状态栏高度,相当于手动实现了 fitsSystemWindows=true 的效果,然后再在根视图加入一个占位视图,其高度也设置为状态栏高度。
//设置 paddingTop
ViewGroup rootView = (ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content);
rootView.setPadding(0, getStatusBarHeight(mActivity), 0, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//5.0 以上直接设置状态栏颜色
activity.getWindow().setStatusBarColor(color);
} else {
//根布局添加占位状态栏
ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView();
View statusBarView = new View(activity);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
getStatusBarHeight(activity));
statusBarView.setBackgroundColor(color);
decorView.addView(statusBarView, lp);
}
不过在状态栏中和actionBar之间会有一点阴影的效果,如果要把它去掉的话。可以直接代码设置:
/**
* 去除 ActionBar 阴影
*/
public StatusBarUtils clearActionBarShadow() {
if (Build.VERSION.SDK_INT >= 21) {
ActionBar supportActionBar = ((AppCompatActivity) mActivity).getSupportActionBar();
if (supportActionBar != null) {
supportActionBar.setElevation(0);
}
}
return this;
}
这是我目前设置状态栏用得较多的方式。当然肯定会有很多其他的实现方式。后续如果需要再补上。下面有一些小米和魅族的
状态栏字体颜色的修改方法
小米:
public void setStatusBarDarkMode(boolean darkmode, Activity activity) {
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);
} catch (Exception e) {
e.printStackTrace();
}
}
魅族
public static boolean setStatusBarDarkIcon(Window window, boolean dark) {
boolean result = false;
if (window != null) {
try {
WindowManager.LayoutParams lp = window.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);
window.setAttributes(lp);
result = true;
} catch (Exception e) {
Log.e("MeiZu", "setStatusBarDarkIcon: failed");
}
}
return result;
}
网友评论