Android開發 android沉浸式狀態欄開發 (google原生/第三方適配/一些其餘問題)

部分轉載原文地址:https://blog.csdn.net/liup1211/article/details/86583015java

 

寫在前面:

1,本文闡述如何實現沉浸式狀態欄

2,部分代碼有從其餘博客摘抄,也有我本身的總結,若侵犯了原做者的權益,請聯繫我刪除

 

下面說一下個人實現步驟android

1,colors

    <color name="colorPrimary">#3F424E</color>
    <color name="colorPrimaryDark">#00000000</color><!--透明-->
    <color name="colorAccent">#FF4081</color>

2,values/styles.xml:

  <style name="AppTheme" parent="AppTheme.Base">
     
    </style>
     
    <style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
     
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/default_bg</item>
    </style>

3,values-v19/styles.xml:

 <style name="AppTheme" parent="AppTheme.Base">
        <!-- Navigation Bar 【false適配某些虛擬按鍵手機】-->
        <item name="android:windowTranslucentNavigation">false</item>
    </style>

4,配置文件使用

    <application
        ... ...
        android:theme="@style/AppTheme"
        ... ...>

 

5,頂部標題欄,一般我會單獨抽出來,關鍵代碼是android:fitsSystemWindows="true"   

這是重點,若是不設置android:fitsSystemWindows="true",可能會出現部分機型標題欄顯示不全的bugapp

<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:contentInsetLeft="0dp"
    app:contentInsetStart="0dp"
    android:fitsSystemWindows="true"
    android:background="?attr/colorPrimary">
     
    ... ...

6,核心代碼(主要來自https://www.jianshu.com/p/a44c119d6ef7,部分是我封裝的)

   import android.annotation.TargetApi;
    import android.app.Activity;
    import android.content.Context;
    import android.content.res.Resources;
    import android.os.Build;
    import android.support.annotation.ColorRes;
    import android.text.TextUtils;
    import android.util.Log;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.Window;
    import android.view.WindowManager;
     
    import com.sandy.cloudlock.R;
     
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.Properties;
     
    public class StatusBarCompatUtil2 {
        private static final int COLOR_DEFAULT = ResourceUtil.getColor(R.color.colorPrimary);
     
        private static int getStatusBarHeight(Context context) {
            int statusBarHeight = 0;
            Resources res = context.getResources();
            int resourceId = res.getIdentifier("status_bar_height", "dimen", "android");
            if (resourceId > 0) {
                statusBarHeight = res.getDimensionPixelSize(resourceId);
            }
            return statusBarHeight;
        }
     
        /**
         * 設置狀態欄透明
         */
        public static void setTranslucentStatus(Activity activity, @ColorRes int statusColor) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Window window = activity.getWindow();
                window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
     
                int color = COLOR_DEFAULT;
                if (statusColor != 0) {
                    color = ResourceUtil.getColor(statusColor);
                }
                window.setStatusBarColor(color);
     
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                int color = COLOR_DEFAULT;
                ViewGroup contentView = activity.findViewById(android.R.id.content);
                if (statusColor != 0) {
                    color = ResourceUtil.getColor(statusColor);
                }
                View statusBarView = new View(activity);
                ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        getStatusBarHeight(activity));
                statusBarView.setBackgroundColor(color);
                contentView.addView(statusBarView, lp);
            } else {
                activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
            }
        }
     
        /**
         * 改變魅族的狀態欄字體爲黑色,要求FlyMe4以上
         */
        private static void processFlyme(Activity activity, boolean darkMode) {
            Window window = activity.getWindow();
            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((Object) null);
                    int value = meizuFlags.getInt(lp);
                    if (darkMode) {
                        value |= bit;
                    } else {
                        value &= ~bit;
                    }
     
                    meizuFlags.setInt(lp, value);
                    window.setAttributes(lp);
     
                } catch (Exception var8) {
                    Log.w("StatusBarUtils", "setStatusBarDarkIcon: failed");
                }
            }
        }
     
        /**
         * 改變小米的狀態欄字體顏色爲黑色, 要求MIUI6以上  lightStatusBar爲真時表示黑色字體
         */
        private static void processMIUI(Activity activity, boolean darkMode) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {   // 即基於 Android 6.0 ,開發版 7.7.13 及之後版本
                compatHighMIUI(activity, darkMode);
            } else {
                compatLowMIUI(activity, darkMode);
            }
        }
     
        @TargetApi(Build.VERSION_CODES.M)
        private static void compatHighMIUI(Activity activity, boolean darkMode) {
            View decorView = activity.getWindow().getDecorView();
            if (darkMode) {
                decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
            } else {
                int flag = decorView.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
                decorView.setSystemUiVisibility(flag);
            }
        }
     
        /**
         * 兼容低版本miui
         *
         * @param activity activity
         * @param darkMode 是否夜間模式
         */
        private static void compatLowMIUI(Activity activity, boolean darkMode) {
            Class<? extends Window> clazz = activity.getWindow().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);
                extraFlagField.invoke(activity.getWindow(), darkMode ? darkModeFlag : 0, darkModeFlag);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
     
        private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
        private static final String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
        private static final String KEY_MIUI_INTERNAL_STORAGE = "ro.miui.internal.storage";
     
        /**
         * 判斷手機是不是小米
         */
        private static boolean isMIUI() {
            final Properties prop = new Properties();
            return prop.getProperty(KEY_MIUI_VERSION_CODE, null) != null
                    || prop.getProperty(KEY_MIUI_VERSION_NAME, null) != null
                    || prop.getProperty(KEY_MIUI_INTERNAL_STORAGE, null) != null;
        }
     
        /**
         * 判斷手機是不是魅族
         *
         * @return
         */
        private static boolean isFlyme() {
            try {
                // Invoke Build.hasSmartBar()
                final Method method = Build.class.getMethod("hasSmartBar");
                return method != null || TextUtils.equals("Meizu", Build.MANUFACTURER);
            } catch (final Exception e) {
                return TextUtils.equals("Meizu", Build.MANUFACTURER);
            }
        }
     
        /**
         * 設置Android狀態欄的字體顏色,狀態欄爲亮色的時候字體和圖標是黑色,狀態欄爲暗色的時候字體和圖標爲白色
         * <p>
         * 設置狀態欄文字色值爲深色調,默認狀態欄顏色透明(即同標題欄的顏色)
         *
         * @param activity    activity
         * @param useDart     是否使用深色調
         */
        public static void setStatusBarFontIconDark(Activity activity, boolean useDart) {
            setStatusBarFontIconDark(activity, useDart, 0);
        }
     
        /**
         * 設置Android狀態欄的字體顏色,狀態欄爲亮色的時候字體和圖標是黑色,狀態欄爲暗色的時候字體和圖標爲白色
         * <p>
         * 設置狀態欄文字色值爲深色調
         *
         * @param activity    activity
         * @param useDart     是否使用深色調
         * @param statusColor 自定義的狀態欄顏色
         */
        public static void setStatusBarFontIconDark(Activity activity, boolean useDart, @ColorRes int statusColor) {
            if (isMIUI()) {
                processMIUI(activity, useDart);
            } else {
                if (isFlyme()) {
                    processFlyme(activity, useDart);
                }
     
                if (useDart) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        int mode = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
                        activity.getWindow().getDecorView().setSystemUiVisibility(mode);
                    }
                } else {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                        int mode = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
                        activity.getWindow().getDecorView().setSystemUiVisibility(mode);
                    }
                }
                activity.getWindow().getDecorView().findViewById(android.R.id.content).setPadding(0, 0, 0, 0);
            }
     
            if (statusColor != 0) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
     
                    int color = ResourceUtil.getColor(statusColor);
                    activity.getWindow().setStatusBarColor(color);
     
                } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    ViewGroup contentView = activity.findViewById(android.R.id.content);
                    int color = ResourceUtil.getColor(statusColor);
                    View statusBarView = new View(activity);
                    ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                            getStatusBarHeight(activity));
                    statusBarView.setBackgroundColor(color);
                    contentView.addView(statusBarView, lp);
                }
            }
     
            ///適配虛擬按鍵背景色
    //        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    //            activity.getWindow().setNavigationBarColor(COLOR_DEFAULT);
    //        }
     
        }
     
    }

7,使用

定義1個activity的超類,在超類的onCreate中調用
setStatusBarFontIconDark(Activity activity, boolean useDart)

狀態欄顏色自定義,調用
setStatusBarFontIconDark(Activity activity, boolean useDart, @ColorRes int statusColor)

如多個fragment切換時,狀態欄顏色不一樣,能夠在fragment的

onActivityCreated (Bundle savedInstanceState)

中調用setStatusBarFontIconDark(Activity activity, boolean useDart, @ColorRes int statusColor)

字體

 

8.問題總結

1.在activity裏使用setContentView方法切換了其餘layout後android:fitsSystemWindows="true"失效的問題

     Rect rectangle = new Rect();
        getWindow().getDecorView().getWindowVisibleDisplayFrame(rectangle);//獲取狀態欄高度
        ConstraintLayout constraintLayout = findViewById(R.id.constraintLayout);//此ConstraintLayout爲xml根Layout
        constraintLayout.setPadding(0, rectangle.top,0,0);

此方法無奈之舉ui

相關文章
相關標籤/搜索