简单利用Support包中的ScrimInsetsFrameLayout,实现状态栏高度捕获和设置颜色

一、前言

之前我的项目有个需求,是要配合 AppBarLayout 的上下滚动缩放,调整 Toolbar 的背景颜色与状态栏颜色,还要适配多 Fragment 切换时状态栏颜色也及时跟进,以实现视觉统一的效果。然后从 Support 包中发现了 ScrimInsetsFrameLayout 这个类,看了源码之后感觉可以为我所用,于是就继承了这个类再加以反射技术,实现了想要的效果。并且目前来看,在效果方面(Android5.0 +)
简单利用Support包中的ScrimInsetsFrameLayout,实现状态栏高度捕获和设置颜色_第1张图片

二、实现

依赖的 Support 包:

compile 'com.android.support:design:26.1.0'
InsetsLayout.java
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;
import android.support.design.internal.ScrimInsetsFrameLayout;
import android.support.v4.view.WindowInsetsCompat;
import android.util.AttributeSet;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Jossing , Create on 2017/10/22
 */
public class InsetsLayout extends ScrimInsetsFrameLayout {

    private List mObserverList;

    public InsetsLayout(Context context) {
        this(context, null);
    }

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

    public InsetsLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mObserverList = new ArrayList<>();
    }

    @Override
    protected void onInsetsChanged(WindowInsetsCompat insets) {
        for (StatusBarHeightObserver observer : mObserverList) {
            observer.update(insets.getSystemWindowInsetTop());
        }
    }

    /**
     * 添加状态栏高度的观察者
     * @param observer 观察者
     */
    public void addObserver(@NonNull StatusBarHeightObserver observer) {
        mObserverList.add(observer);
    }

    /**
     * 移除指定的观察者
     * @param observer 观察者
     */
    public void removeObserver(@NonNull StatusBarHeightObserver observer) {
        mObserverList.remove(observer);
    }

    /**
     * 清空观察者
     */
    public void clearObserver() {
        mObserverList.clear();
    }

    /**
     * 设置状态栏下面 View 的前景颜色
     * @param color 指定颜色的 16 进制整数值
     */
    public void setInsetForegroundColor(@ColorInt int color) {
        setInsetForeground(new ColorDrawable(color));
    }

    /**
     * 设置状态栏下面 View 的前景颜色
     * @param colorId 指定颜色的资源 id
     */
    public void setInsetForegroundColorId(@ColorRes int colorId) {
        setInsetForeground(new ColorDrawable(getResources().getColor(colorId)));
    }

    /**
     * 设置状态栏下面 View 的前景
     * @param insetForeground 前景可绘制对象
     */
    public void setInsetForeground(@NonNull Drawable insetForeground) {
        try {
            Field field = getClass().getSuperclass().getDeclaredField("mInsetForeground");
            field.setAccessible(true);
            field.set(this, insetForeground);
        } catch (Exception e) {
            e.printStackTrace();
        }
        invalidate();
    }

    /**
     * 获取状态栏下面 View 的前景
     * @return 状态栏下面 View 的前景
     */
    public Drawable getInsetForeground() {
        try {
            Field field = getClass().getSuperclass().getDeclaredField("mInsetForeground");
            field.setAccessible(true);
            return (Drawable)field.get(this);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 状态栏高度变化的回调接口
     */
    public interface StatusBarHeightObserver {

        /**
         * 当状态栏高度发生变化时回调这个方法
         * @param statusBarHeight 状态栏高度的像素值
         */
        void update(int statusBarHeight);
    }
}

三、使用

1. 布局文件 xxxx.xml



<android.support.v4.widget.DrawerLayout
    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">

    <yourpackage.InsetsLayout
        android:id="@+id/contentFrame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        app:insetForeground="#0000" />

android.support.v4.widget.DrawerLayout>
2. 在 Activity 里面
private InsetsLayout mInsetsLayout;

private void xxx() {
    mInsetsLayout = (InsetsLayout) findViewById(R.id.contentFrame);

    //设置状态栏颜色
    // mInsetsLayout.setInsetForeground(new BitmapDrawable());
    // mInsetsLayout.setInsetForegroundColor(Color.RED);
    mInsetsLayout.setInsetForegroundColorId(R.color.colorPrimaryDark);

    //添加状态栏高度观察者
    mInsetsLayout.addObserver(new InsetsLayout.StatusBarHeightObserver() {
        @Override
        public void update(int statusBarHeight) {
            //这里获取到的这个 int 值就是状态栏的高度了(px)
            Log.i("statusBarHeight", statusBarHeight);
        }
    }
}

四、最后

代码介绍不多,但都有注释,大家应该都好理解。实现的那部分代码里面,有用到 Java 反射技术,还不懂的朋友不妨先自行了解反射,再回来看这篇博客。如果有好的建议呢,欢迎大家在评论区留言回复,或者联系我。
~~谢谢大家。

【不允许转载!不允许转载!不允许转载!】

你可能感兴趣的:(Android)