经过这些年的摸爬滚打,总算在最新的项目中实现了真正的沉浸式,也许有人比我更早,但是我不管你,我只管我(明学家)!
我写这个博客的目的就是让大家复制过去,直接调用就实现,当然该明白的也得明白。
又转眼到了11月下旬,这个项目也优化的差不多了,可能有些小页面没有发现,咱也不细追了。只是在首页呀随着轮播图改变状态栏颜色的这个功能做的真不错,只是没有完美的沉浸,因为状态栏明显比轮播图背景多了一层灰色,嘿嘿,你看碰到我了。。。
沉浸式最早是在android4.4上出现,但是5.0之后又做了修改,所以我们一般做判断的分界线就是4.4和5.0,我这边貌似只适配到4.4,因为实在找不到4.4以下的手机去测试啦!
众所周知,现在都是9012年的尾巴了,网上各种沉浸式状态栏的文章是多如牛毛,我曾经也各种复制各种实验,奈何无果,所以不是所有的文章都那么良心的啦,当然我也没啥良心。
首先沉浸式要设置没有标题栏的主题,这样方便自己控制颜色。
<style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
style>
目前代码可以分为两部分,一部分是针对状态栏高度的,这个用不用看个人喜好。另一部分是修改状态栏颜色的。
话说了很多,上代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:fitsSystemWindows="true"
android:clipToPadding="true"
android:orientation="vertical">
</LinearLayout>
根布局添加android:fitsSystemWindows=“true”,如果设置为true会在你的根布局上加入状态栏高度的空白,设置为false你的根布局就会紧贴屏幕顶部,和时间什么的重叠。
若是不想用上面的办法,可以在根布局加入一个view,然后动态设置他的高度,好处也是获取到这个view可以随便的改颜色,例如首页四个fragment中有点要显示状态栏,有的不显示状态,切换一下又要换颜色等等。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<View
android:id="@+id/statuTop"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
可以在activity中用下面的方法动态改变它的高度。
/**
* 反射获取任务栏高度设置给view
* @param statuTop
*/
public void setStatuTop(View statuTop) {
if (statuTop != null) {
int size = getResources().getDimensionPixelSize(getResources().getIdentifier("status_bar_height", "dimen", "android"));
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) statuTop.getLayoutParams();
//用margin或padding的话状态栏颜色不好控制
// layoutParams.topMargin = size;
// statuTop.setPadding(0, size, 0, 0);
layoutParams.height = size;
statuTop.setLayoutParams(layoutParams);
}
}
我的一系列代码都写在BaseActivity里面,不像别人还弄个util,我是那种连util都懒得调的人,何况这个状态栏只在activity中用呢。
话不多说,先上代码:
/**
* 设置任务栏字体颜色
* @param isDark 这里的是否黑色,如果是黑色背景传true字体就会白色,不是传false字体黑色
*/
protected void setStatuDark(boolean isDark) {
setStatuDark(Color.TRANSPARENT, isDark);
}
/**
* 设置任务栏颜色和字体颜色
* @param color 可以自定义颜色
* @param isDark 这里的是否黑色,如果是黑色背景传true字体就会白色,不是传false字体黑色
*/
protected void setStatuDark(int color, boolean isDark) {
if (MIUISetStatusBarLightMode(this, isDark)) {
} else if (FlymeSetStatusBarLightMode(getWindow(), isDark)) {
} else {
if (isDark) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
// activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//解决Android5.0以上,状态栏设置颜色后变灰的问题
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(color);
} else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
}
/**
* 适配小米沉浸式
* @param activity
* @param dark
* @return
*/
protected boolean MIUISetStatusBarLightMode(Activity activity, boolean dark) {
boolean isMIUI = false;
Window window = activity.getWindow();
if (window != null) {
Class clazz = window.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);
if (dark) {
extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
} else {
extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体
}
isMIUI = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//开发版 7.7.13 及以后版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上
if (dark) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
}
} catch (Exception e) {
}
}
return isMIUI;
}
/**
* 适配魅族沉浸式
*
* @param window
* @param dark
* @return
*/
protected boolean FlymeSetStatusBarLightMode(Window window, boolean dark) {
boolean isFlyme = 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);
isFlyme = true;
} catch (Exception e) {
}
}
return isFlyme;
}
调用的时候这么写。
public class TestActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
//setStatuTop(statuTop);
setStatuDark(true);
}
}
就这么简单就实现了,其实还可以扩展,根据当前状态栏颜色自动调整字体颜色。
/**
* 设置任务栏颜色,根据颜色明亮自动调整状态栏字体颜色
* @param color
*/
protected void setStatuColor(int color) {
setStatuDark(ColorUtils.calculateLuminance(color) >= 0.5);
}
另外提一嘴,ColorUtils和ArgbEvaluator真是好用。。。处理一切颜色