还用第三方库管理状态栏吗?Android关于状态栏管理的几种方案实现!

语言: CN / TW / HK

theme: juejin highlight: a11y-dark


我正在参与掘金创作者训练营第6期,点击了解活动详情

前言

在我们开发应用的过程中,关于状态栏的管理是不得不提的事情,一般我们通过开源的一些第三方库来管理,并没有了解它实现原理。

image.png

状态栏说的就是我们顶部的那个大黑边了,一个应用的状态栏,我们一般常用的几种操作如下:

  1. 设置状态栏的背景颜色(如果是6.0以下需要兼容处理白色背景)
  2. 设置状态栏的背景图片
  3. 设置状态栏开启沉浸式和关闭沉浸式
  4. 设置状态栏文本图标颜色(黑色与白色)
  5. 设置指定布局适配状态栏高度

一般来说操作状态栏有两种思路,一种是直接操作系统状态栏,一般使用一个工具类来实现。另一种是弃用系统状态,使用宿主自定义View的方案代替 DecorView 中的真正布局,间距的操作'状态栏'。这里的状态栏打引号,因为这个状态栏是我们自定义View实现的。

下面我们来看看他们分别如何实现与操作。

一、系统原生状态栏

由于Android的状态栏处理不同的系统版本处理的方式不同,这里只兼容到4.4版本以上,也是我们常用的最低版本。

1.1 状态栏管理工具类

一般我们通过状态栏的工具类添加一些Flag,操作管理系统的状态栏。

```java /* * 状态栏透明,状态栏黑色文字,状态栏颜色,沉浸式状态栏 / public class StatusBarUtils {

public static int DEFAULT_COLOR = 0;
public static float DEFAULT_ALPHA = 0;

/**
 * 设置状态栏背景颜色
 */
public static void setColor(Activity activity, @ColorInt int color) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        activity.getWindow().setStatusBarColor(color);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        ViewGroup systemContent = 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);
        systemContent.getChildAt(0).setFitsSystemWindows(true);
        systemContent.addView(statusBarView, 0, lp);
    }
}


public static void immersive(Activity activity) {
    immersive(activity, DEFAULT_COLOR, DEFAULT_ALPHA);
}

public static void immersive(Activity activity, int color, @FloatRange(from = 0.0, to = 1.0) float alpha) {
    immersive(activity.getWindow(), color, alpha);
}

public static void immersive(Activity activity, int color) {
    immersive(activity.getWindow(), color, 1f);
}

public static void immersive(Window window) {
    immersive(window, DEFAULT_COLOR, DEFAULT_ALPHA);
}

public static void immersive(Window window, int color) {
    immersive(window, color, 1f);
}

public static void immersive(Window window, int color, @FloatRange(from = 0.0, to = 1.0) float alpha) {
    if (Build.VERSION.SDK_INT >= 21) {
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        window.setStatusBarColor(mixtureColor(color, alpha));

        int systemUiVisibility = window.getDecorView().getSystemUiVisibility();
        systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
        systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
        window.getDecorView().setSystemUiVisibility(systemUiVisibility);
    } else if (Build.VERSION.SDK_INT >= 19) {
        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        setTranslucentView((ViewGroup) window.getDecorView(), color, alpha);
    } else if (Build.VERSION.SDK_INT > 16) {
        int systemUiVisibility = window.getDecorView().getSystemUiVisibility();
        systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
        systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
        window.getDecorView().setSystemUiVisibility(systemUiVisibility);
    }
}

/**
 * 创建假的透明栏
 */
public static void setTranslucentView(ViewGroup container, int color, @FloatRange(from = 0.0, to = 1.0) float alpha) {
    if (Build.VERSION.SDK_INT >= 19) {
        int mixtureColor = mixtureColor(color, alpha);
        View translucentView = container.findViewById(android.R.id.custom);
        if (translucentView == null && mixtureColor != 0) {
            translucentView = new View(container.getContext());
            translucentView.setId(android.R.id.custom);
            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(container.getContext()));
            container.addView(translucentView, lp);
        }
        if (translucentView != null) {
            translucentView.setBackgroundColor(mixtureColor);
        }
    }
}

public static int mixtureColor(int color, @FloatRange(from = 0.0, to = 1.0) float alpha) {
    int a = (color & 0xff000000) == 0 ? 0xff : color >>> 24;
    return (color & 0x00ffffff) | (((int) (a * alpha)) << 24);
}

// ========================  状态栏字体颜色设置  ↓ ================================


/**
 * 设置状态栏黑色字体图标
 */
public static boolean setStatusBarBlackText(Activity activity) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Window window = activity.getWindow();
        View decorView = window.getDecorView();

        decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);

        return true;
    }
    return false;
}

/**
 * 设置状态栏白色字体图标
 */
public static boolean setStatusBarWhiteText(Activity activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Window window = activity.getWindow();
        View decorView = window.getDecorView();

        decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);

        return true;
    }
    return false;
}

// ========================  状态栏字体颜色设置  ↑================================


// 在某些机子上存在不同的density值,所以增加两个虚拟值
private static int sStatusBarHeight = -1;
private static float sVirtualDensity = -1;
private final static int STATUS_BAR_DEFAULT_HEIGHT_DP = 25; // 大部分状态栏都是25dp

/**
 * 获取状态栏的高度。
 */
public static int getStatusBarHeight(Context context) {
    if (sStatusBarHeight == -1) {
        initStatusBarHeight(context);
    }
    return sStatusBarHeight;
}

private static void initStatusBarHeight(Context context) {
    Class<?> clazz;
    Object obj = null;
    Field field = null;
    try {
        clazz = Class.forName("com.android.internal.R$dimen");
        obj = clazz.newInstance();
        if (DeviceUtils.isMeizu()) {
            try {
                field = clazz.getField("status_bar_height_large");
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        if (field == null) {
            field = clazz.getField("status_bar_height");
        }
    } catch (Throwable t) {
        t.printStackTrace();
    }
    if (field != null && obj != null) {
        try {
            int id = Integer.parseInt(field.get(obj).toString());
            sStatusBarHeight = context.getResources().getDimensionPixelSize(id);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
    if (DeviceUtils.isTablet(context)
            && sStatusBarHeight > CommUtils.dip2px(STATUS_BAR_DEFAULT_HEIGHT_DP)) {
        //状态栏高度大于25dp的平板,状态栏通常在下方
        sStatusBarHeight = 0;
    } else {
        if (sStatusBarHeight <= 0) {
            if (sVirtualDensity == -1) {
                sStatusBarHeight = CommUtils.dip2px(STATUS_BAR_DEFAULT_HEIGHT_DP);
            } else {
                sStatusBarHeight = (int) (STATUS_BAR_DEFAULT_HEIGHT_DP * sVirtualDensity + 0.5f);
            }
        }
    }
}


// ========================  适配状态栏高度  ↓ ================================

/**
 * 适配状态栏高度的View - 设置Padding
 */
public static void fitsStatusBarViewPadding(View view) {
    //增加高度
    ViewGroup.LayoutParams lp = view.getLayoutParams();
    lp.height += getStatusBarHeight(view.getContext());

    //设置PaddingTop
    view.setPadding(view.getPaddingLeft(),
            view.getPaddingTop() + getStatusBarHeight(view.getContext()),
            view.getPaddingRight(),
            view.getPaddingBottom());
}

/**
 * 适配状态栏高度的View - 设置Margin
 */
public static void fitsStatusBarViewMargin(View view) {

    if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {

        //已经添加过了不要再次设置
        if (view.getTag() != null && view.getTag().equals("fitStatusBar")) {
            return;
        }

        ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
        int marginTop = layoutParams.topMargin;
        int setMarginTop = marginTop + getStatusBarHeight(view.getContext());
        view.setTag("fitStatusBar");
        layoutParams.topMargin = setMarginTop;
        view.requestLayout();
    }
}

/**
 * 适配状态栏高度的View - 使用布局包裹
 */
public static void fitsStatusBarViewLayout(View view) {

    ViewParent fitParent = view.getParent();
    if (fitParent != null) {

        if (((fitParent instanceof LinearLayout) &&
                ((ViewGroup) fitParent).getTag() != null &&
                ((ViewGroup) fitParent).getTag().equals("fitLayout"))) {
            //已经添加过了不要再次设置
            return;
        }

        //给当前布局包装一个适应布局
        ViewGroup fitGroup = (ViewGroup) fitParent;
        fitGroup.removeView(view);

        LinearLayout fitLayout = new LinearLayout(view.getContext());
        fitLayout.setOrientation(LinearLayout.VERTICAL);
        fitLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        fitLayout.setTag("fitLayout");

        //先加一个状态栏高度的布局
        View statusView = new View(view.getContext());
        statusView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(view.getContext())));
        fitLayout.addView(statusView);

        ViewGroup.LayoutParams fitViewParams = view.getLayoutParams();
        fitLayout.addView(view);

        fitGroup.addView(fitLayout);
    }
}

}

```

1.2 系统状态栏的背景和文本颜色处理

通过工具类操作的形式,我们一般封装到BaseActivity中,比如定义一些方法:

```kotlin /* * 设置顶部状态栏的颜色(默认为白色背景-黑色文字) / protected fun setStatusBarColor(): Int { //如果状态栏文字能变黑那么背景设置为白色,否则返回背景灰色文本默认为白色 return if (StatusBarUtils.setStatusBarBlackText(this)) { Color.WHITE } else { Color.parseColor("#B0B0B0") } }

/**
 * 动态的设置状态栏颜色
 * 当颜色为白色的时候显示白底黑字
 * 其他颜色为其他颜色底白色字
 * 一般由子类重写
 */
fun setStatusBarColor(color: Int) {

    if (color == Color.WHITE) {
        //变黑色文字成功
        if (StatusBarUtils.setStatusBarBlackText(this)) {
            StatusBarUtils.setColor(this, Color.WHITE)
        } else {
            StatusBarUtils.setColor(this, Color.parseColor("#B0B0B0"))
        }

    } else {

        //变为白色文字成功
        StatusBarUtils.setStatusBarWhiteText(this)
        StatusBarUtils.setColor(this, color)

    }
}

fun setStatusBarBlackText(){
    StatusBarUtils.setStatusBarBlackText(this)
}

fun setStatusBarWhiteText(){
    StatusBarUtils.setStatusBarWhiteText(this)
}

```

我们可以再基类中使用默认的状态栏背景颜色、文本颜色。然后子类想重写的话直接调用方法设置即可,一般来说就能满足我们的需求。

关于状态栏文本颜色6.0以下是无法修改为黑色的文本的(没有使用魅族小米的兼容方案,没必要,如果大家想要魅族小米4.4 - 6.0的黑色文本兼容,可以网上找找,也可以留言),需要做一下兼容,当低版本设置状态栏背景颜色为白色的时候,我们修改为灰色展示即可。

image.png

通过基类的封装,我们确实可以很方便的实现状态栏中背景颜色与文本颜色的处理,那么沉浸式的处理如何解决呢?

1.3 系统状态栏的沉浸式处理

一般沉浸式的处理,我们在oncreate方法中调用工具类方法。

kotlin StatusBarUtils.setStatusBarWhiteText(this) StatusBarUtils.immersive(this)

确实是实现了沉浸式,一般情况下也就够用了,但是如果我们需求变化,或者框架变化,就会有问题,这样的沉浸式如果设置了就不能取消,如果我们的场景是顶部的Title和状态栏是一张图片背景,然后下面的列表滚动到图片消失之后状态栏不沉浸式了,状态栏背景颜色变为白色,这...

或者我们使用的是单Activity+多Fragment的框架,我们一个Activity中的根Fragment设置为沉浸式,那么在其他的子Fragment中我们又不需要沉浸式。这...

一般在这样的方案中我们可以通过自定义的状态栏View,和自定义的TitleBar的解决。

可以使用标准TitleBar的页面,我们可以通过TitleBar设置对应的状态栏,例如:

kotlin <com.guadou.lib_baselib.view.titlebar.EasyTitleBar android:layout_width="match_parent" android:layout_height="wrap_content" app:Easy_hasStatusPadding="true" app:Easy_title="吐司-弹窗-banner" app:Easy_titleBarBackground="#ff0000" />

例如 hasStatusPadding 属性。就是可以自由的设置TitleBar顶部的状态栏间距。就可以自由的控制状态栏的高度与颜色或背景的变化。

但是如果我们顶部是自定义的布局,比如搜索框 + lottie动画之类的整体布局,那我们怎么办?

此处就需要使用我们自定义的状态栏布局:

```java public class StatusbarGrayView extends View {

public StatusbarGrayView(Context context) {
    super(context);
}

public StatusbarGrayView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
}

public StatusbarGrayView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int widthMode = MeasureSpec.getMode(widthMeasureSpec); //得到宽度设置模式
    int widthSize = MeasureSpec.getSize(widthMeasureSpec); //得到宽度设置模式
    int heightMode = MeasureSpec.getMode(heightMeasureSpec); //得到高度设置模式

    //如果设置高度为wrap-content自适应 那么固定设置为状态栏高度
    if (heightMode == MeasureSpec.AT_MOST) {
        if (widthMode == MeasureSpec.EXACTLY) {
            setMeasuredDimension(widthSize, EasyUtil.getStateBarHeight(getContext()));
        } else {
            setMeasuredDimension(1, EasyUtil.getStateBarHeight(getContext()));
        }
    } else {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    ViewGroup parent = (ViewGroup) getParent();
    if (parent == null) return;
    Drawable drawable = parent.getBackground();
    if (drawable instanceof ColorDrawable) {
        int color = ((ColorDrawable) drawable).getColor();

        if (color == Color.WHITE || color == CommUtils.getColor(R.color.white)) {

            setBackgroundColor(Build.VERSION.SDK_INT < 23 ? CommUtils.getColor(R.color.status_bar_gray_bg) : Color.WHITE);

        } else {
            setBackgroundColor(Color.TRANSPARENT);
        }
    } else {
        setBackgroundColor(Color.TRANSPARENT);
    }

}

}

```

我们使用自定义View,放在自定义搜索框Title的上面即可实现状态高度的自由控制,

到此我们就能把Activity全部沉浸式,然后由自定义的TitleBar来管理我们的状态,或者有自定义状态View来管理状态栏。

到此系统状态栏的管理已经能实现绝大部分的效果处理,缺点是实现的方案不统一吗,不同的效果需要不同的方案来解决,如果是别人接手你的项目可能会比较蒙。

而另一种方案也是我比较推荐的方案就是使用宿主的形式代替系统的状态栏布局。

二、自定义宿主管理状态栏

具体的方案是,我们setContentView的时候,把系统的DecorView中的View取出,替换成我们自定义的布局,内部包括一个自定义的状态栏,和一个FramLayout,我们把之前的布局取出添加到我们自定义布局中,然后默认把当前Activity沉浸式之后,当下操作的StatusBar就是我们的自定义StatusBarView了。

这样操作状态栏就是操作我们的View对象了,想怎么玩就怎么玩,更加灵活了,设置颜色,Drawable,Alpha等都是非常的方便,想设置沉浸式直接Gone掉我们的自定义StatusBarView即可,想不用沉浸式,那么就把StatusBarView设置为VISIBLE即可。

并且对状态栏的各种操作不受到系统版本影响,就一个字,灵活!

定义我们自定义状态栏View对象 ```java /* * 自定义状态栏的View,用于StatusBarHostLayout中使用 / class StatusView extends View {

private int mBarSize;

public StatusView(Context context) {
    this(context, null, 0);
}

public StatusView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public StatusView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    mBarSize = StatusBarHostUtils.getStatusBarHeight(context);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mBarSize);
}

//获取到当前的状态栏高度
public int getStatusBarHeight() {
    return mBarSize;
}

} ```

核心的宿主代替类: ```java /* * 宿主的布局 / @SuppressLint("ViewConstructor") public class StatusBarHostLayout extends LinearLayout {

private Activity mActivity;
private StatusView mStatusView;
private FrameLayout mContentLayout;

StatusBarHostLayout(Activity activity) {
    super(activity);

    this.mActivity = activity;

    //加载自定义的宿主布局
    if (mStatusView == null && mContentLayout == null) {
        setOrientation(LinearLayout.VERTICAL);

        mStatusView = new StatusView(mActivity);
        mStatusView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        addView(mStatusView);

        mContentLayout = new FrameLayout(mActivity);
        mContentLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f));
        addView(mContentLayout);
    }

    //替换宿主的contentView为外界设置的View
    replaceContentView();

    //设置原生的状态栏沉浸式,使用自定义的状态栏布局
    StatusBarHostUtils.immersiveStatusBar(mActivity);
    StatusBarHostUtils.setStatusBarColor(mActivity, Color.TRANSPARENT);
}

private void replaceContentView() {
    Window window = mActivity.getWindow();
    ViewGroup contentLayout = window.getDecorView().findViewById(Window.ID_ANDROID_CONTENT);
    if (contentLayout.getChildCount() > 0) {
        //先找到DecorView的容器移除掉已经设置的ContentView
        View contentView = contentLayout.getChildAt(0);
        contentLayout.removeView(contentView);
        ViewGroup.LayoutParams contentParams = contentView.getLayoutParams();

        //外部设置的ContentView添加到宿主中来
        mContentLayout.addView(contentView, contentParams.width, contentParams.height);
    }
    //再把整个宿主添加到Activity对应的DecorView中去
    contentLayout.addView(this, -1, -1);
}


/**
 * 设置状态栏文本颜色为黑色
 */
public StatusBarHostLayout setStatusBarBlackText() {
    StatusBarHostUtils.setStatusBarDarkFont(mActivity, true);
    return this;
}

/**
 * 设置状态栏文本颜色为白色
 */
public StatusBarHostLayout setStatusBarWhiteText() {
    StatusBarHostUtils.setStatusBarDarkFont(mActivity, false);
    return this;
}

/**
 * 设置自定义状态栏布局的背景颜色
 */
public StatusBarHostLayout setStatusBarBackground(int color) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        mStatusView.setBackgroundColor(color);
    } else {
        //6.0以下不能白色状态栏
        YYLogUtils.w("当前的状态颜色1:" + color);
        if (color == Color.WHITE) {
            color = Color.parseColor("#B0B0B0");
        }

        mStatusView.setBackgroundColor(color);
    }

    return this;
}

/**
 * 设置自定义状态栏布局的背景图片
 */
public StatusBarHostLayout setStatusBarBackground(Drawable drawable) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        mStatusView.setBackground(drawable);
    } else {
        mStatusView.setBackgroundDrawable(drawable);
    }
    return this;
}

/**
 * 设置自定义状态栏布局的透明度
 */
public StatusBarHostLayout setStatusBarBackgroundAlpha(int alpha) {
    Drawable background = mStatusView.getBackground();
    if (background != null) {
        background.mutate().setAlpha(alpha);
    }
    return this;
}

/**
 * 给指定的布局适配状态栏高度,设置paddingTop
 */
public StatusBarHostLayout setViewFitsStatusBarView(View view) {

    //设置MaginTop的方式
    if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {

        //已经添加过了不要再次设置
        if (view.getTag() != null && view.getTag().equals("fitStatusBar")) {
            return this;
        }

        ViewGroup.MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
        int marginTop = layoutParams.topMargin;
        int setMarginTop = marginTop + mStatusView.getStatusBarHeight();
        view.setTag("fitStatusBar");
        layoutParams.topMargin = setMarginTop;
        view.requestLayout();
    }

    return this;
}


/**
 * 设置自定义状态栏的沉浸式
 */
public StatusBarHostLayout setStatusBarImmersive(boolean needImmersive) {
    layoutimmersive(needImmersive);
    return this;
}

//具体的沉浸式逻辑
private void layoutimmersive(boolean needImmersive) {

    if (needImmersive) {
        mStatusView.setVisibility(GONE);
    } else {
        mStatusView.setVisibility(VISIBLE);
        mStatusView.setBackgroundColor(ContextCompat.getColor(mActivity, R.color.colorPrimary));
    }

}

} ```

定义一个状态栏设置入口: ```java /* * 宿主替换布局的方式管理状态栏与内容的布局 / public class StatusBarHost {

private StatusBarHost() {
}

public static StatusBarHostLayout inject(Activity activity) {
    Window window = activity.getWindow();
    ViewGroup contentLayout = window.getDecorView().findViewById(Window.ID_ANDROID_CONTENT);
    if (contentLayout.getChildCount() > 0) {
        View contentView = contentLayout.getChildAt(0);
        //如果当前是宿主的包装类,直接强转
        if (contentView instanceof StatusBarHostLayout) {
            return (StatusBarHostLayout) contentView;
        }
    }
    //如果不是我们封装一个宿主包装类
    return new StatusBarHostLayout(activity);
}

} ```

就简单的三个类即可完成状态栏的管理,内部的工具类和上面的工具类类似,只需要沉浸式的处理与状态栏文本颜色的切换。

下面看看如何使用:

什么都不加的默认效果

image.png

我们加上状态栏颜色白色 kotlin val hostLayout = StatusBarHost.inject(this) .setStatusBarBackground(color(R.color.white)) .setStatusBarBlackText()

效果如下:

image.png

如果是6.0版本一下,是这样的效果

image.png

切换状态栏颜色为红色

```kotlin findViewById(R.id.btn_bg_color).click {

        hostLayout.setStatusBarBackground(Color.RED)
    }

```

效果:

image.png

由于是我们自己的View,我们还能设置状态栏背景Drawable ```kotlin findViewById(R.id.btn_bg_img).click {

        hostLayout.setStatusBarBackground(getDrawable(R.drawable.statusbar_image_1))
    }

```

效果如下:

image.png

6.0 一下的效果也是一样的

image.png

沉浸式的处理,一句话就可以:

kotlin val hostLayout = StatusBarHost.inject(this) .setStatusBarImmersive(true)

效果:

image.png

那我们取消沉浸式: ```kotlin findViewById(R.id.btn_002).click {

        hostLayout.setStatusBarImmersive(false)
    }

```

效果:

image.png

我们可以自由的设置View的状态栏间距

kotlin findViewById<View>(R.id.btn_003).click { hostLayout.setViewFitsStatusBarView(findViewById(R.id.title_view)) }

效果:

image.png image.png

滚动渐变状态栏颜色: ```kotlin override fun init() {

    val startColor: Int = color(R.color.white)
    val endColor: Int = color(R.color.colorPrimary)

    //默认的状态处理
    hostLayout = StatusBarHost.inject(this)
        .setStatusBarBackground(startColor)
        .setStatusBarWhiteText()


    //监听滚动
    val myScrollView = findViewById<NestedScrollView>(R.id.my_scroll)
    easyTitleBar = findViewById(R.id.easy_title)
    easyTitleBar.setBackgroundColor(startColor)
    val topImg = findViewById<ImageView>(R.id.iv_top_img)

    SizeUtils.forceGetViewSize(topImg) {
        imgHeight = it.height
    }

    myScrollView.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->

        if (imgHeight > 0) {

            val scrollDistance = Math.min(scrollY, imgHeight)

            val fraction: Float = scrollDistance.toFloat() / imgHeight.toFloat()

            setTitleStatusBarAlpha(CalculateUtils.evaluate(fraction, startColor, endColor))
        }

    })

}

private fun setTitleStatusBarAlpha(color: Int) {
    easyTitleBar.setBackgroundColor(color)
    hostLayout.setStatusBarBackground(color)
}

```

6.0 以上效果:

scroll_02.gif

6.0 以下效果:

scroll_04.gif

可以看到相比系统状态栏的管理,我们使用宿主的方案一样的可以全部实现,并且使用起来方式更加的统一,更加的便捷一些。

总结

两种方案都可以,看大家习惯使用的是哪一种方案。

如果是管理系统的状态栏,那么我们在一些特殊场景和单Activity的架构中就没有那么灵活,需要配合自定义的TitleBar和自定义StatusBarView来处理。

如果是使用宿主方案管理状态栏,那么我们使用起来兼容性会更好一些,但是我们需要理解它实现的原理,才能更方便和灵活的做出对应的操作,需要有一些学习成本。

你们用的都是哪一种方案呢?

本文全部代码都已全部贴出,如果大家有兴趣也可以查看源码自取。

好了,本期内容如讲的不到位或错漏的地方,希望同学们可以指出交流。

如果感觉本文对你有一点点点的启发,还望你能点赞支持一下,你的支持是我最大的动力。

Ok,这一期就此完结。

「其他文章」