最近在开发中遇到一种个性化的需求, 类似于 QQ 顶部的渐变状态栏的实现, 如下图
首先我们要了解在 Android5.0 以后, 系统 API 提供直接设置 StatusBar 来改变状态栏的颜色, 然而在 4.4 上 StatusBar 变色的基本原理就是将 StatusBar 本身设置为透明, 然后在 StatusBar 的位置添加一个相同大小的 View 并上色. 没办法, 我们要做的渐变颜色状态栏就是要兼容上下版本的差异
更多关于沉浸式状态栏的了解可参考洪洋大神的文章
Android 沉浸式状态栏攻略 让你的状态栏变色吧
纯色兼容状态栏
代码如下
- /**
- * 设置状态栏颜色
- *
- * @param activity 需要设置的 activity
- * @param color 状态栏颜色值
- * @param statusBarAlpha 状态栏透明度
- */
- public static void setColor(Activity activity, @ColorInt int color, @IntRange(from = 0, to = 255) int statusBarAlpha) {
- if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.LOLLIPOP) {
- //5.0 以上版本
- // 设置 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 属性才能调用 setStatusBarColor 方法来设置状态栏颜色
- activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- // 设置 FLAG_TRANSLUCENT_STATUS 透明状态栏
- activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- // 根据输入的颜色和透明度显示
- activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha));
- } else if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.KITKAT) {
- // 低版本
- // 添加透明状态栏
- activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- // 获取顶级视图
- ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
- // 获取顶部的 StatusBarView, 自定义 StatusBarView 的 Id(在 resources 中创建 Id)
- View fakeStatusBarView = decorView.findViewById(R.id.statusbarutil_fake_status_bar_view);
- if (fakeStatusBarView != null) {
- if (fakeStatusBarView.getVisibility() == View.GONE) {
- fakeStatusBarView.setVisibility(View.VISIBLE);
- }
- // 设置顶层颜色
- fakeStatusBarView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
- } else {
- // 上述不符合, 则创建一个 View 添加到顶级视图中
- decorView.addView(createStatusBarView(activity, color, statusBarAlpha));
- }
- setRootView(activity);
- }
- }
- calculateStatusColor(计算状态栏颜色)
- /**
- * 计算状态栏颜色
- *
- * @param color color 值
- * @param alpha alpha 值
- * @return 最终的状态栏颜色
- */
- private static int calculateStatusColor(@ColorInt int color, int alpha) {
- if (alpha == 0) {
- return color;
- }
- float a = 1 - alpha / 255f;
- int red = color>> 16 & 0xff;
- int green = color>> 8 & 0xff;
- int blue = color & 0xff;
- red = (int) (red * a + 0.5);
- green = (int) (green * a + 0.5);
- blue = (int) (blue * a + 0.5);
- return 0xff <<24 | red << 16 | green << 8 | blue;
- }
自定义 View 状态栏
- /**
- * 自定义 View 状态栏
- *
- * @param activity 需要设置的 activity
- * @param color 状态栏颜色值
- * @param alpha 透明值
- * @return 状态栏矩形条
- */
- private static View createStatusBarView(Activity activity, @ColorInt int color, int alpha) {
- // 绘制一个和状态栏一样高的矩形
- View statusBarView = new View(activity);
- LinearLayout.LayoutParams params =
- new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
- statusBarView.setLayoutParams(params);
- statusBarView.setBackgroundColor(calculateStatusColor(color, alpha));
- // 自定义的 StatusBarView 的 Id
- statusBarView.setId(FAKE_STATUS_BAR_VIEW_ID);
- return statusBarView;
- }
最后重新规划布局
- setRootView
- /**
- * 设置根布局参数
- */
- private static void setRootView(Activity activity) {
- //ViewGroup 容器存放 UI 组件
- ViewGroup parent = (ViewGroup) activity.findViewById(Android.R.id.content);
- for (int i = 0, count = parent.getChildCount(); i < count; i++) {
- View childView = parent.getChildAt(i);
- if (childView instanceof ViewGroup) {
- childView.setFitsSystemWindows(true);
- ((ViewGroup) childView).setClipToPadding(true);
- }
- }
- }
由此纯色状态栏的基本配置就可以了, 只需要创建 Utils 工具类在 Activity 中调用即可,
- // 设置纯色状态栏
- StatusBarUtil.setColor(this, AppUtils.getColor(R.color.colorPrimary));
渐变色兼容状态栏
关于渐变颜色的状态栏, 实现方法有很多种, 比如 (反射拿到 StatusBar 并设置 setBackgroundResource 将 shape 渐变颜色添加进来即可, 创建 View 填充状态栏), 这里我们介绍的是第二种方法, 创建 View 填充状态栏 (有没有方法跟上面的方法很类似)
代码如下
- /**
- * 为界面设置自定义透明 View
- *
- * @param activity 需要设置的 activity
- * @param statusBarAlpha 状态栏透明度
- * @param needOffsetView 需要向下偏移的 View
- public static void setTranslucentForWindow(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha,
- View needOffsetView) {
- if (Build.VERSION.SDK_INT> Build.VERSION_CODES.KITKAT) {
- //5.0 以上版本
- setTransparentForWindow(activity);
- addTranslucentView(activity, statusBarAlpha);
- if (needOffsetView != null) {
- Object haveSetOffset = needOffsetView.getTag(TAG_KEY_HAVE_SET_OFFSET);
- if (haveSetOffset != null && (Boolean) haveSetOffset) {
- return;
- }
- ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) needOffsetView.getLayoutParams();
- layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin + getStatusBarHeight(activity),
- layoutParams.rightMargin, layoutParams.bottomMargin);
- needOffsetView.setTag(TAG_KEY_HAVE_SET_OFFSET, true);
- }
- } else {
- // 低版本
- // 添加透明状态栏
- activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- // 获取顶级视图
- ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
- // 获取顶部的 StatusBarView, 自定义 id
- View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID);
- if (fakeStatusBarView != null) {
- if (fakeStatusBarView.getVisibility() == View.GONE) {
- fakeStatusBarView.setVisibility(View.VISIBLE);
- }
- // 设置顶层颜色
- fakeStatusBarView.setBackgroundResource(R.drawable.shape_gradient);
- } else {
- // 上述不符合, 则创建一个 View 添加到顶级视图中
- View statusBarView = new View(activity);
- LinearLayout.LayoutParams params =
- new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
- statusBarView.setLayoutParams(params);
- fakeStatusBarView.setBackgroundResource(R.drawable.shape_gradient);
- statusBarView.setId(FAKE_STATUS_BAR_VIEW_ID);
- decorView.addView(statusBarView);
- }
- setRootView(activity);
- }
- }
- getStatusBarHeight
- /**
- * 获取状态栏高度
- *
- * @param context context
- * @return 状态栏高度
- */
- public static int getStatusBarHeight(Context context) {
- // 获得状态栏高度
- int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
- return context.getResources().getDimensionPixelSize(resourceId);
- }
- setTransparentForWindow
- /**
- * 设置透明
- */
- public static void setTransparentForWindow(Activity activity) {
- if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.LOLLIPOP) {
- activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
- activity.getWindow()
- .getDecorView()
- .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- } else if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.KITKAT) {
- activity.getWindow()
- .setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- }
- addTranslucentView
- /**
- * 添加半透明矩形条
- *
- * @param activity 需要设置的 activity
- * @param statusBarAlpha 透明值
- */
- private static void addTranslucentView(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) {
- ViewGroup contentView = (ViewGroup) activity.findViewById(Android.R.id.content);// 系统 Id
- View fakeTranslucentView = contentView.findViewById(FAKE_TRANSLUCENT_VIEW_ID);
- if (fakeTranslucentView != null) {
- if (fakeTranslucentView.getVisibility() == View.GONE) {
- fakeTranslucentView.setVisibility(View.VISIBLE);
- }
- fakeTranslucentView.setBackgroundColor(Color.argb(statusBarAlpha, 0, 0, 0));
- } else {
- contentView.addView(createTranslucentStatusBarView(activity, statusBarAlpha));
- }
- }
由此渐变颜色的状态栏设置, 只需要将 toolbar 作为 View 传入, 调用如下
- // 设置渐变颜色状态栏
- StatusBarUtil.setTransparentForWindow(this, mToolbar);
- // 布局如下
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- 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="wrap_content">
- <Android.support.design.widget.AppBarLayout
- Android:layout_width="match_parent"
- Android:layout_height="wrap_content"
- Android:background="@drawable/shape_gradient"
- Android:theme="@style/AppTheme.AppBarOverlay"
- App:elevation="@dimen/dp0">
- <Android.support.v7.widget.Toolbar
- Android:id="@+id/toolbar"
- Android:layout_width="match_parent"
- Android:layout_height="?attr/actionBarSize"
- App:popupTheme="@style/ToolbarPopupTheme"
- App:title="@string/main_toolbar_title_top"
- App:titleTextColor="@color/colorPrimary">
- </Android.support.v7.widget.Toolbar>
- </Android.support.design.widget.AppBarLayout>
- </LinearLayout>
至此, 渐变色状态栏的配置已经介绍完全了, 说实话刚开始做的时候, 还真的没想到用自定义 View 延伸到状态栏中显示, 但细想下纯色状态栏中的实现也有类似的操作, 再结合一下就实现了兼容上下版本的效果
来源: http://www.jianshu.com/p/3364a18b2643