项目中经常需要状态栏沉浸式解决方案,网上很多解决方案的文章,现在总结一种实际项目中可行的方案:

1、前期准备

全局搜索你的代码里 是否有 android:fitsSystemWindow,如果有就删掉。

检查你的values、values-v19、values-v21等 是否配置了如下item标签:

// values-v19。v19 开始有 android:windowTranslucentStatus 这个属性

// values-v21。5.0 以上提供了 setStatusBarColor()  方法设置状态栏颜色。

凡是在style.xml中 有关 windowTranslucentNavigation、windowTranslucentStatus、statusBarColor 统统删掉,因为我们要通过代码去实现, xml中的各种属性全部不要写, 避免代码出现互相干扰, 会出现各种无效等的bug。

2、需要的工具类

1) githup下载SystemBarTint库中SystemBarTintManager.java类

地址:https://github.com/jgilfelt/SystemBarTint/blob/master/library/src/com/readystatesoftware/systembartint/SystemBarTintManager.java

package com.cmcc.cmii.util;import android.annotation.SuppressLint;import android.annotation.TargetApi;import android.app.Activity;import android.content.Context;import android.content.res.Configuration;import android.content.res.Resources;import android.content.res.TypedArray;import android.graphics.drawable.Drawable;import android.os.Build;import android.util.DisplayMetrics;import android.util.TypedValue;import android.view.Gravity;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewGroup;import android.view.Window;import android.view.WindowManager;import android.widget.FrameLayout.LayoutParams;import java.lang.reflect.Method;/** * author :king * date : 2019/11/7 14:40 * description :Class to manage status and navigation bar tint effects when using KitKat *  translucent system UI modes. */public class SystemBarTintManager {    static {        // Android allows a system property to override the presence of the navigation bar.        // Used by the emulator.        // See https://github.com/android/platform_frameworks_base/blob/master/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#L1076        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            try {                Class c = Class.forName("android.os.SystemProperties");                Method m = c.getDeclaredMethod("get", String.class);                m.setAccessible(true);                sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys");            } catch (Throwable e) {                sNavBarOverride = null;            }        }    }    /**     * The default system bar tint color value.     */    public static final int DEFAULT_TINT_COLOR = 0x99000000;    private static String sNavBarOverride;    private final SystemBarConfig mConfig;    private boolean mStatusBarAvailable;    private boolean mNavBarAvailable;    private boolean mStatusBarTintEnabled;    private boolean mNavBarTintEnabled;    private View mStatusBarTintView;    private View mNavBarTintView;    /**     * Constructor. Call this in the host activity onCreate method after its     * content view has been set. You should always create new instances when     * the host activity is recreated.     *     * @param activity The host activity.     */    @SuppressLint("ResourceType")    @TargetApi(19)    public SystemBarTintManager(Activity activity) {        Window win = activity.getWindow();        ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            // check theme attrs            int[] attrs = {android.R.attr.windowTranslucentStatus,                    android.R.attr.windowTranslucentNavigation};            TypedArray a = activity.obtainStyledAttributes(attrs);            try {                mStatusBarAvailable = a.getBoolean(0, false);                mNavBarAvailable = a.getBoolean(1, false);            } finally {                a.recycle();            }            // check window flags            WindowManager.LayoutParams winParams = win.getAttributes();            int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;            if ((winParams.flags & bits) != 0) {                mStatusBarAvailable = true;            }            bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;            if ((winParams.flags & bits) != 0) {                mNavBarAvailable = true;            }        }        mConfig = new SystemBarConfig(activity, mStatusBarAvailable, mNavBarAvailable);        // device might not have virtual navigation keys        if (!mConfig.hasNavigtionBar()) {            mNavBarAvailable = false;        }        if (mStatusBarAvailable) {            setupStatusBarView(activity, decorViewGroup);        }        if (mNavBarAvailable) {            setupNavBarView(activity, decorViewGroup);        }    }    /**     * Enable tinting of the system status bar.     *     * If the platform is running Jelly Bean or earlier, or translucent system     * UI modes have not been enabled in either the theme or via window flags,     * then this method does nothing.     *     * @param enabled True to enable tinting, false to disable it (default).     */    public void setStatusBarTintEnabled(boolean enabled) {        mStatusBarTintEnabled = enabled;        if (mStatusBarAvailable) {            mStatusBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);        }    }    /**     * Enable tinting of the system navigation bar.     *     * If the platform does not have soft navigation keys, is running Jelly Bean     * or earlier, or translucent system UI modes have not been enabled in either     * the theme or via window flags, then this method does nothing.     *     * @param enabled True to enable tinting, false to disable it (default).     */    public void setNavigationBarTintEnabled(boolean enabled) {        mNavBarTintEnabled = enabled;        if (mNavBarAvailable) {            mNavBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);        }    }    /**     * Apply the specified color tint to all system UI bars.     *     * @param color The color of the background tint.     */    public void setTintColor(int color) {        setStatusBarTintColor(color);        setNavigationBarTintColor(color);    }    /**     * Apply the specified drawable or color resource to all system UI bars.     *     * @param res The identifier of the resource.     */    public void setTintResource(int res) {        setStatusBarTintResource(res);        setNavigationBarTintResource(res);    }    /**     * Apply the specified drawable to all system UI bars.     *     * @param drawable The drawable to use as the background, or null to remove it.     */    public void setTintDrawable(Drawable drawable) {        setStatusBarTintDrawable(drawable);        setNavigationBarTintDrawable(drawable);    }    /**     * Apply the specified alpha to all system UI bars.     *     * @param alpha The alpha to use     */    public void setTintAlpha(float alpha) {        setStatusBarAlpha(alpha);        setNavigationBarAlpha(alpha);    }    /**     * Apply the specified color tint to the system status bar.     *     * @param color The color of the background tint.     */    public void setStatusBarTintColor(int color) {        if (mStatusBarAvailable) {            mStatusBarTintView.setBackgroundColor(color);        }    }    /**     * Apply the specified drawable or color resource to the system status bar.     *     * @param res The identifier of the resource.     */    public void setStatusBarTintResource(int res) {        if (mStatusBarAvailable) {            mStatusBarTintView.setBackgroundResource(res);        }    }    /**     * Apply the specified drawable to the system status bar.     *     * @param drawable The drawable to use as the background, or null to remove it.     */    @SuppressWarnings("deprecation")    public void setStatusBarTintDrawable(Drawable drawable) {        if (mStatusBarAvailable) {            mStatusBarTintView.setBackgroundDrawable(drawable);        }    }    /**     * Apply the specified alpha to the system status bar.     *     * @param alpha The alpha to use     */    @TargetApi(11)    public void setStatusBarAlpha(float alpha) {        if (mStatusBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {            mStatusBarTintView.setAlpha(alpha);        }    }    /**     * Apply the specified color tint to the system navigation bar.     *     * @param color The color of the background tint.     */    public void setNavigationBarTintColor(int color) {        if (mNavBarAvailable) {            mNavBarTintView.setBackgroundColor(color);        }    }    /**     * Apply the specified drawable or color resource to the system navigation bar.     *     * @param res The identifier of the resource.     */    public void setNavigationBarTintResource(int res) {        if (mNavBarAvailable) {            mNavBarTintView.setBackgroundResource(res);        }    }    /**     * Apply the specified drawable to the system navigation bar.     *     * @param drawable The drawable to use as the background, or null to remove it.     */    @SuppressWarnings("deprecation")    public void setNavigationBarTintDrawable(Drawable drawable) {        if (mNavBarAvailable) {            mNavBarTintView.setBackgroundDrawable(drawable);        }    }    /**     * Apply the specified alpha to the system navigation bar.     *     * @param alpha The alpha to use     */    @TargetApi(11)    public void setNavigationBarAlpha(float alpha) {        if (mNavBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {            mNavBarTintView.setAlpha(alpha);        }    }    /**     * Get the system bar configuration.     *     * @return The system bar configuration for the current device configuration.     */    public SystemBarConfig getConfig() {        return mConfig;    }    /**     * Is tinting enabled for the system status bar?     *     * @return True if enabled, False otherwise.     */    public boolean isStatusBarTintEnabled() {        return mStatusBarTintEnabled;    }    /**     * Is tinting enabled for the system navigation bar?     *     * @return True if enabled, False otherwise.     */    public boolean isNavBarTintEnabled() {        return mNavBarTintEnabled;    }    private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {        mStatusBarTintView = new View(context);        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());        params.gravity = Gravity.TOP;        if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {            params.rightMargin = mConfig.getNavigationBarWidth();        }        mStatusBarTintView.setLayoutParams(params);        mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);        mStatusBarTintView.setVisibility(View.GONE);        decorViewGroup.addView(mStatusBarTintView);    }    private void setupNavBarView(Context context, ViewGroup decorViewGroup) {        mNavBarTintView = new View(context);        LayoutParams params;        if (mConfig.isNavigationAtBottom()) {            params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getNavigationBarHeight());            params.gravity = Gravity.BOTTOM;        } else {            params = new LayoutParams(mConfig.getNavigationBarWidth(), LayoutParams.MATCH_PARENT);            params.gravity = Gravity.RIGHT;        }        mNavBarTintView.setLayoutParams(params);        mNavBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);        mNavBarTintView.setVisibility(View.GONE);        decorViewGroup.addView(mNavBarTintView);    }    /**     * Class which describes system bar sizing and other characteristics for the current     * device configuration.     *     */    public static class SystemBarConfig {        private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";        private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height";        private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape";        private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width";        private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar";        private final boolean mTranslucentStatusBar;        private final boolean mTranslucentNavBar;        private final int mStatusBarHeight;        private final int mActionBarHeight;        private final boolean mHasNavigationBar;        private final int mNavigationBarHeight;        private final int mNavigationBarWidth;        private final boolean mInPortrait;        private final float mSmallestWidthDp;        private SystemBarConfig(Activity activity, boolean translucentStatusBar, boolean traslucentNavBar) {            Resources res = activity.getResources();            mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);            mSmallestWidthDp = getSmallestWidthDp(activity);            mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME);            mActionBarHeight = getActionBarHeight(activity);            mNavigationBarHeight = getNavigationBarHeight(activity);            mNavigationBarWidth = getNavigationBarWidth(activity);            mHasNavigationBar = (mNavigationBarHeight > 0);            mTranslucentStatusBar = translucentStatusBar;            mTranslucentNavBar = traslucentNavBar;        }        @TargetApi(14)        private int getActionBarHeight(Context context) {            int result = 0;            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {                TypedValue tv = new TypedValue();                context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);                result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics());            }            return result;        }        @TargetApi(14)        private int getNavigationBarHeight(Context context) {            Resources res = context.getResources();            int result = 0;            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {                if (hasNavBar(context)) {                    String key;                    if (mInPortrait) {                        key = NAV_BAR_HEIGHT_RES_NAME;                    } else {                        key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME;                    }                    return getInternalDimensionSize(res, key);                }            }            return result;        }        @TargetApi(14)        private int getNavigationBarWidth(Context context) {            Resources res = context.getResources();            int result = 0;            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {                if (hasNavBar(context)) {                    return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME);                }            }            return result;        }        @TargetApi(14)        private boolean hasNavBar(Context context) {            Resources res = context.getResources();            int resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android");            if (resourceId != 0) {                boolean hasNav = res.getBoolean(resourceId);                // check override flag (see static block)                if ("1".equals(sNavBarOverride)) {                    hasNav = false;                } else if ("0".equals(sNavBarOverride)) {                    hasNav = true;                }                return hasNav;            } else { // fallback                return !ViewConfiguration.get(context).hasPermanentMenuKey();            }        }        private int getInternalDimensionSize(Resources res, String key) {            int result = 0;            int resourceId = res.getIdentifier(key, "dimen", "android");            if (resourceId > 0) {                result = res.getDimensionPixelSize(resourceId);            }            return result;        }        @SuppressLint("NewApi")        private float getSmallestWidthDp(Activity activity) {            DisplayMetrics metrics = new DisplayMetrics();            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {                activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);            } else {                // TODO this is not correct, but we don't really care pre-kitkat                activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);            }            float widthDp = metrics.widthPixels / metrics.density;            float heightDp = metrics.heightPixels / metrics.density;            return Math.min(widthDp, heightDp);        }        /**         * Should a navigation bar appear at the bottom of the screen in the current         * device configuration? A navigation bar may appear on the right side of         * the screen in certain configurations.         *         * @return True if navigation should appear at the bottom of the screen, False otherwise.         */        public boolean isNavigationAtBottom() {            return (mSmallestWidthDp >= 600 || mInPortrait);        }        /**         * Get the height of the system status bar.         *         * @return The height of the status bar (in pixels).         */        public int getStatusBarHeight() {            return mStatusBarHeight;        }        /**         * Get the height of the action bar.         *         * @return The height of the action bar (in pixels).         */        public int getActionBarHeight() {            return mActionBarHeight;        }        /**         * Does this device have a system navigation bar?         *         * @return True if this device uses soft key navigation, False otherwise.         */        public boolean hasNavigtionBar() {            return mHasNavigationBar;        }        /**         * Get the height of the system navigation bar.         *         * @return The height of the navigation bar (in pixels). If the device does not have         * soft navigation keys, this will always return 0.         */        public int getNavigationBarHeight() {            return mNavigationBarHeight;        }        /**         * Get the width of the system navigation bar when it is placed vertically on the screen.         *         * @return The width of the navigation bar (in pixels). If the device does not have         * soft navigation keys, this will always return 0.         */        public int getNavigationBarWidth() {            return mNavigationBarWidth;        }        /**         * Get the layout inset for any system UI that appears at the top of the screen.         *         * @param withActionBar True to include the height of the action bar, False otherwise.         * @return The layout inset (in pixels).         */        public int getPixelInsetTop(boolean withActionBar) {            return (mTranslucentStatusBar ? mStatusBarHeight : 0) + (withActionBar ? mActionBarHeight : 0);        }        /**         * Get the layout inset for any system UI that appears at the bottom of the screen.         *         * @return The layout inset (in pixels).         */        public int getPixelInsetBottom() {            if (mTranslucentNavBar && isNavigationAtBottom()) {                return mNavigationBarHeight;            } else {                return 0;            }        }        /**         * Get the layout inset for any system UI that appears at the right of the screen.         *         * @return The layout inset (in pixels).         */        public int getPixelInsetRight() {            if (mTranslucentNavBar && !isNavigationAtBottom()) {                return mNavigationBarWidth;            } else {                return 0;            }        }    }2)OSUtils工具类package com.cmcc.cmii.util;import android.os.Build;import android.text.TextUtils;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;/** * author :king * date : 2019/11/7 14:43 * description : */public class OSUtils {    public static final String ROM_MIUI = "MIUI";    public static final String ROM_EMUI = "EMUI";    public static final String ROM_FLYME = "FLYME";    public static final String ROM_OPPO = "OPPO";    public static final String ROM_SMARTISAN = "SMARTISAN";    public static final String ROM_VIVO = "VIVO";    public static final String ROM_QIKU = "QIKU";    private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name";    private static final String KEY_VERSION_EMUI = "ro.build.version.emui";    private static final String KEY_VERSION_OPPO = "ro.build.version.opporom";    private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version";    private static final String KEY_VERSION_VIVO = "ro.vivo.os.version";    private static String sName;    private static String sVersion;    public static boolean isEmui() {        return check(ROM_EMUI);    }    public static boolean isMiui() {        return check(ROM_MIUI);    }    public static boolean isVivo() {        return check(ROM_VIVO);    }    public static boolean isOppo() {        return check(ROM_OPPO);    }    public static boolean isFlyme() {        return check(ROM_FLYME);    }    public static boolean is360() {        return check(ROM_QIKU) || check("360");    }    public static boolean isSmartisan() {        return check(ROM_SMARTISAN);    }    public static String getName() {        if (sName == null) {            check("");        }        return sName;    }    public static String getVersion() {        if (sVersion == null) {            check("");        }        return sVersion;    }    public static boolean check(String rom) {        if (sName != null) {            return sName.equals(rom);        }        if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) {            sName = ROM_MIUI;        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) {            sName = ROM_EMUI;        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) {            sName = ROM_OPPO;        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) {            sName = ROM_VIVO;        } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) {            sName = ROM_SMARTISAN;        } else {            sVersion = Build.DISPLAY;            if (sVersion.toUpperCase().contains(ROM_FLYME)) {                sName = ROM_FLYME;            } else {                sVersion = Build.UNKNOWN;                sName = Build.MANUFACTURER.toUpperCase();            }        }        return sName.equals(rom);    }    public static String getProp(String name) {        String line = null;        BufferedReader input = null;        try {            Process p = Runtime.getRuntime().exec("getprop " + name);            input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);            line = input.readLine();            input.close();        } catch (IOException ex) {            return null;        } finally {            if (input != null) {                try {                    input.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return line;    }}3) 兼容4.x以上沉浸透明状态栏的一个兼容类package com.cmcc.cmii.util;import android.annotation.SuppressLint;import android.annotation.TargetApi;import android.app.Activity;import android.content.Context;import android.graphics.Color;import android.os.Build;import android.support.annotation.IntDef;import android.view.View;import android.view.ViewGroup;import android.view.Window;import android.view.WindowManager;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.reflect.Field;import java.lang.reflect.Method;/** * author :king * date : 2019/11/7 14:39 * description : */public class StatusBarUtil {    public final static int TYPE_MIUI = 0;    public final static int TYPE_FLYME = 1;    public final static int TYPE_M = 3;//6.0    @IntDef({TYPE_MIUI,            TYPE_FLYME,            TYPE_M})    @Retention(RetentionPolicy.SOURCE)    @interface ViewType {    }    /**     * 修改状态栏颜色,支持4.4以上版本     *     * @param colorId 颜色     */    public static void setStatusBarColor(Activity activity, int colorId) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {            Window window = activity.getWindow();            window.setStatusBarColor(colorId);        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            //使用SystemBarTintManager,需要先将状态栏设置为透明            setTranslucentStatus(activity);            SystemBarTintManager systemBarTintManager = new SystemBarTintManager(activity);            systemBarTintManager.setStatusBarTintEnabled(true);//显示状态栏            systemBarTintManager.setStatusBarTintColor(colorId);//设置状态栏颜色        }    }    /**     * 设置状态栏透明     */    @TargetApi(19)    public static void setTranslucentStatus(Activity activity) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {            //5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色            Window window = activity.getWindow();            View decorView = window.getDecorView();            //两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;            decorView.setSystemUiVisibility(option);            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);            window.setStatusBarColor(Color.TRANSPARENT);            //导航栏颜色也可以正常设置            //window.setNavigationBarColor(Color.TRANSPARENT);        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            Window window = activity.getWindow();            WindowManager.LayoutParams attributes = window.getAttributes();            int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;            attributes.flags |= flagTranslucentStatus;            //int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;            //attributes.flags |= flagTranslucentNavigation;            window.setAttributes(attributes);        }    }    /**     *  代码实现android:fitsSystemWindows     *     * @param activity     */    public static void setRootViewFitsSystemWindows(Activity activity, boolean fitSystemWindows) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            ViewGroup winContent = (ViewGroup) activity.findViewById(android.R.id.content);            if (winContent.getChildCount() > 0) {                ViewGroup rootView = (ViewGroup) winContent.getChildAt(0);                if (rootView != null) {                    rootView.setFitsSystemWindows(fitSystemWindows);                }            }        }    }    /**     * 设置状态栏深色浅色切换     */    public static boolean setStatusBarDarkTheme(Activity activity, boolean dark) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {                setStatusBarFontIconDark(activity, TYPE_M, dark);            } else if (OSUtils.isMiui()) {                setStatusBarFontIconDark(activity, TYPE_MIUI, dark);            } else if (OSUtils.isFlyme()) {                setStatusBarFontIconDark(activity, TYPE_FLYME, dark);            } else {//其他情况                return false;            }            return true;        }        return false;    }    /**     * 设置 状态栏深色浅色切换     */    public static boolean setStatusBarFontIconDark(Activity activity, @ViewType int type,boolean dark) {        switch (type) {            case TYPE_MIUI:                return setMiuiUI(activity, dark);            case TYPE_FLYME:                return setFlymeUI(activity, dark);            case TYPE_M:            default:                return setCommonUI(activity,dark);        }    }    //设置6.0 状态栏深色浅色切换    public static boolean setCommonUI(Activity activity, boolean dark) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {            View decorView = activity.getWindow().getDecorView();            if (decorView != null) {                int vis = decorView.getSystemUiVisibility();                if (dark) {                    vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;                } else {                    vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;                }                if (decorView.getSystemUiVisibility() != vis) {                    decorView.setSystemUiVisibility(vis);                }                return true;            }        }        return false;    }    //设置Flyme 状态栏深色浅色切换    public static boolean setFlymeUI(Activity activity, boolean dark) {        try {            Window window = activity.getWindow();            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);            return true;        } catch (Exception e) {            e.printStackTrace();            return false;        }    }    //设置MIUI 状态栏深色浅色切换    public static boolean setMiuiUI(Activity activity, boolean dark) {        try {            Window window = activity.getWindow();            Class<?> clazz = activity.getWindow().getClass();            @SuppressLint("PrivateApi") Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");            Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");            int darkModeFlag = field.getInt(layoutParams);            Method extraFlagField = clazz.getDeclaredMethod("setExtraFlags", int.class, int.class);            extraFlagField.setAccessible(true);            if (dark) {    //状态栏亮色且黑色字体                extraFlagField.invoke(window, darkModeFlag, darkModeFlag);            } else {                extraFlagField.invoke(window, 0, darkModeFlag);            }            return true;        } catch (Exception e) {            e.printStackTrace();            return false;        }    }    //获取状态栏高度    public static int getStatusBarHeight(Context context) {        int result = 0;        int resourceId = context.getResources().getIdentifier(                "status_bar_height", "dimen", "android");        if (resourceId > 0) {            result = context.getResources().getDimensionPixelSize(resourceId);        }        return result;    }}这个类支持了设置状态栏透明, 设置状态栏颜色, 支持了状态栏深色浅色切换(则状态栏上的文字图标颜色)

3、使用

首先在Activity 的setContentView 下一行编写如下代码(一般你可以写到你的BaseActivity里,否则你每个activity都得写一次)

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.xxx);
   
   //注意调用setRootViewFitsSystemWindows里面 winContent.getChildCount()=0 导致代码无法继续
   //是因为你需要在setContentView之后才可以调用 setRootViewFitsSystemWindows 
   
   //当FitsSystemWindows设置 true 时,会在屏幕最上方预留出状态栏高度的 padding
   StatusBarUtil.setRootViewFitsSystemWindows(this,true);
   //设置状态栏透明
   StatusBarUtil.setTranslucentStatus(this);
   //一般的手机的状态栏文字和图标都是白色的, 可如果你的应用也是纯白色的, 或导致状态栏文字看不清
   //所以如果你是这种情况,请使用以下代码, 设置状态使用深色文字图标风格, 否则你可以选择性注释掉这个if内容
   if (!StatusBarUtil.setStatusBarDarkTheme(this, true)) {
        //如果不支持设置深色风格 为了兼容总不能让状态栏白白的看不清, 于是设置一个状态栏颜色为半透明,
        //这样半透明+白=灰, 状态栏的文字能看得清
        StatusBarUtil.setStatusBarColor(this,0x55000000);
   } 
}


由于界面风格很多, 比如同一个app有的界面是黑色风格的页面, 有的是白色风格的页面,有的是顶部是图片的界面希望沉浸进去, 同时此时状态栏文字要跟随改变。

比如4个不同的fragment,有一个是白色,一个是黑色, 另外两个是顶部是图片的

你还可以随时使用StatusBarUtil.setStatusBarColor(this,颜色值);设置不同fragment时 的状态栏颜色

前面设置了setRootViewFitsSystemWindows(this,true)带有 paddingTop=状态栏高度的效果,如果顶部不是图片布局 , 可以直接使用 setStatusBarColo设置相同颜色即可
如果顶部是图片布局, 想要图片沉浸, 必须设置fitsSystemWindows=false, 以去掉padding效果, 然后想办法 把图片上层的 其他View 整体 paddingTop=状态栏高 让其他View向下挪动。

当前带图片的activity重新设置setRootViewFitsSystemWindows(this,false);效果如下(你会发现图标跑左边了 ),去掉padding效果后图片沉浸了! 但内容进入了状态栏里被遮挡.

怎么以最方便的方式 让整个内容布局 往下挪动?

有很多教程都是写的是在代码里 findView,然后设置padding , 很是麻烦, 要是多个界面都这样代码岂止乱?在xml中使用状态栏高度值 ,结果发现这是几乎是不可能的, 因为编译后xml固定了值,除非使用反射, 但这到了安卓9.0不能反射系统api怎么办?

解决方案:自定义一个View ,用来做状态栏高度占位

/**
 * 功能:状态栏高度View,用于沉浸占位
 */

public class StatusBarHeightView extends LinearLayout {
    private int statusBarHeight;
    private int type;

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

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

    public StatusBarHeightView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr);
        init(attrs);


    }

    private void init(@Nullable AttributeSet attrs) {

        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            if(resourceId>0) {
                statusBarHeight = getResources().getDimensionPixelSize(resourceId);
            }
        }else{
            //低版本 直接设置0
            statusBarHeight = 0;
        }
        if (attrs != null) {
            TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.StatusBarHeightView);
            type = typedArray.getInt(R.styleable.StatusBarHeightView_use_type, 0);
            typedArray.recycle();
        }
        if (type == 1) {
            setPadding(getPaddingLeft(), statusBarHeight, getPaddingRight(), getPaddingBottom());
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (type == 0) {
            setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                    statusBarHeight);
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
 
}


attrs.xml


       
           
           
       
   

 

解释下两个类型:
use_height: 设置当前布局高度=状态栏高度值 用于无子View时的占位
use_padding_top: 设置当前顶部padding=状态栏高度值 用于有子View时的占位
适配低于4.4时 占位View的高度为0 所以不可见

使用方法, 用StatusBarHeightView 来包住你要往下移动的内容! 单独留出要沉浸的View不包住,
举例:

    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >        
          
              android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@mipmap/icon_top_bg"
        android:scaleType="centerCrop" />
                    

             android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_marginEnd="@dimen/widget_size_5"
        app:use_type="use_padding_top"
        android:orientation="vertical" >
        
                        android:id="@+id/ivUserShare"
              android:layout_width="@dimen/title_height"
              android:layout_height="@dimen/title_height"
              android:padding="@dimen/widget_size_10"
              android:src="@mipmap/icon_share_white" />
                        
    

//不要忘记了, 在当前activity onCreate中设置 取消padding,  因为这个padding 我们用代码实现了,不需要系统帮我
StatusBarUtil.setRootViewFitsSystemWindows(this,false);

如果你按上面去做, 状态栏颜色无法被修改, 请检查上层布局是否设置了背景或者受了全局主题的

@color/xxx

的颜色影响

更多相关文章

  1. android Button 样式
  2. 关于那些Android中不常用的设置属性
  3. 横屏和竖屏切换界面不刷新
  4. Android(安卓)Property System | Android属性系统
  5. TextView 属性
  6. Android系统服务-WindowManager
  7. andriod EditText的属性[转]
  8. android:imeOptions属性
  9. android渐变色,边角,边框,

随机推荐

  1. android > 建立WIFI 热点
  2. android 输入法的使用
  3. 几个Android小错误解决方法
  4. android 获取手机中的联系人
  5. android framework在launcher中隐藏指定a
  6. 首先要感谢 lordhong proper carlosbdw
  7. 美图秀秀自由拼图android实现
  8. android 自带图标介绍
  9. android 仿写 screen lock
  10. android 解析 xml 文档的三种方法