偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Android進階之沉浸式狀態(tài)欄原理和使用詳解

移動開發(fā) Android
Android系統(tǒng)4.4之前狀態(tài)欄一直是黑色的,在4.4中帶來了 windowTranslucentStatus 這一特性,開始引出“沉浸式狀態(tài)欄”這個概念。Google 在 Android 4.4 的 API 描述頁面里提到了“Translucent system UI styling”,即透明化的系統(tǒng)UI風格。

[[416377]]

本文轉載自微信公眾號「Android開發(fā)編程」,作者Android開發(fā)編程。轉載本文請聯(lián)系Android開發(fā)編程公眾號。

前言

沉浸式就是要給用戶提供完全沉浸的體驗,使用戶有一種置身于虛擬世界之中的感覺;

這種體驗在各類游戲中被廣泛應用,絕大部分的游戲都會在打開后,使得屏幕被完全被游戲占據(jù),讓玩家沉浸其中,從體驗上沉浸式效果會更好一些;

網上很多人都寫過沉浸式原理的文章,講解的都不是很清晰,讓人很費解;

今天我們就來徹底的總結下沉浸式實現(xiàn)和原理;

一、沉浸式概念和為何要用沉浸式

1、沉浸式概念

  • Android系統(tǒng)4.4之前狀態(tài)欄一直是黑色的,在4.4中帶來了 windowTranslucentStatus 這一特性,開始引出“沉浸式狀態(tài)欄”這個概念。Google 在 Android 4.4 的 API 描述頁面里提到了“Translucent system UI styling”,即透明化的系統(tǒng)UI風格。
  • “沉浸式狀態(tài)欄”準確來說應該是“透明欄”,是 4.4 新定義的設計規(guī)范;
  • 簡單來說就是在軟件打開的時候通知欄和軟件頂部顏色融為一體,這樣可以使軟件和系統(tǒng)本身更加符合,同時通知欄的顏色不再是白色、黑色簡單的兩種了;
  • 沉浸式表示全屏顯示手機屏幕是沒有手機里面自帶的任何控件;

2、為何要用沉浸式

  • 如果App里面目前都沒有做沉浸式狀態(tài)欄,會導致狀態(tài)欄呈黑色條狀,而且下面這個的黑色(白色)條狀與App主界面有很明顯的區(qū)別。這樣在一定程度上犧牲了視覺高度,界面面積變小,最主要的是用戶的視覺和體驗;
  • 說白了,用戶體驗好,用的爽,留存就高,那么領導肯定讓開發(fā)沉浸式主題樣式;

二、沉浸式原理和兼容

從Android4.4 到現(xiàn)在(Android 7.1),關于沉浸式大概可以分成三個階段:

  • Android4.4(API 19) - Android 5.0(API 21):這個階段可以實現(xiàn)沉浸式,但是表現(xiàn)得還不是很好,實現(xiàn)方式為: 通過FLAG_TRANSLUCENT_STATUS設置狀態(tài)欄為透明并且為全屏模式,然后通過添加一個與StatusBar 一樣大小的View,將View 的 background 設置為我們想要的顏色,從而來實現(xiàn)沉浸式;
  • Android 5.0(API 21)以上版本:在Android 5.0的時候,加入了一個重要的屬性和方法 android:statusBarColor (對應方法為 setStatusBarColor),通過這個方法我們就可以輕松實現(xiàn)沉浸式。也就是說,從Android5.0開始,系統(tǒng)才真正的支持沉浸式;
  • Android 6.0(API 23)以上版本:其實Android6.0以上的實現(xiàn)方式和Android 5.0 +是一樣,為什么要將它歸為一個單獨重要的階段呢?是因為從Android 6.0(API 23)開始,我們可以改狀態(tài)欄的繪制模式,可以顯示白色或淺黑色的內容和圖標(除了魅族手機,魅族自家有做源碼更改,6.0以下就能實現(xiàn));

1、Android4.4(API 19)- Android 5.0(API 21)

Android在4.4新增了一個重要的屬性:FLAG_TRANSLUCENT_STATUS

  1. /** 
  2.   * Window flag: request a translucent status bar with minimal system-provided 
  3.   * background protection. 
  4.   * 
  5.   * <p>This flag can be controlled in your theme through the 
  6.   * {@link android.R.attr#windowTranslucentStatus} attribute; this attribute 
  7.   * is automatically set for you in the standard translucent decor themes 
  8.   * such as 
  9.   * {@link android.R.style#Theme_Holo_NoActionBar_TranslucentDecor}, 
  10.   * {@link android.R.style#Theme_Holo_Light_NoActionBar_TranslucentDecor}, 
  11.   * {@link android.R.style#Theme_DeviceDefault_NoActionBar_TranslucentDecor}, and 
  12.   * {@link android.R.style#Theme_DeviceDefault_Light_NoActionBar_TranslucentDecor}.</p> 
  13.   * 
  14.   * <p>When this flag is enabled for a window, it automatically sets 
  15.   * the system UI visibility flags {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and 
  16.   * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.</p> 
  17.   */ 
  18.  public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000; 

設置狀態(tài)欄透明,并且變?yōu)槿聊J健.斶@個屬性有效的時候,會自動設置 system ui visibility的標志SYSTEM_UI_FLAG_LAYOUT_STABLE和SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 。

通過 FLAG_TRANSLUCENT_STATUS 設置狀態(tài)欄為透明并且為全屏模式,然后通過添加一個與 StatusBar 一樣大小的 View,將 View 的 backgroud 設置為我們想要的顏色,從而實現(xiàn)沉浸式。

①, 設置 FLAG_TRANSLUCENT_STATUS,可以在代碼中設置,如下:

  1. activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 

或者可以在 theme 設置屬性 windowTranslucentStatus,如下:

②.根據(jù)有需要,設置一個和 StatusBar 一樣大小的占位 View,如果不設置則內容 View 會向上頂一個 StattusBar 的高度。

圖片延伸到狀態(tài)欄只需要設置FLAG_TRANSLUCENT_STATUS就可以

添加占位View的代碼如下:

  1. //獲取decorView 
  2.         ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); 
  3.         int count = decorView.getChildCount(); 
  4.         //判斷是否已經添加了statusBarView 
  5.         if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) { 
  6.             decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha)); 
  7.         } else { 
  8.             //新建一個和狀態(tài)欄高寬的view 
  9.             StatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha); 
  10.             decorView.addView(statusView); 
  11.         } 
  12.         ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0); 
  13.         //rootview不會為狀態(tài)欄留出狀態(tài)欄空間 
  14.         ViewCompat.setFitsSystemWindows(rootView,true); 
  15.         rootView.setClipToPadding(true); 
  16. private static StatusBarView createStatusBarView(Activity activity, int color, int alpha) { 
  17.         // 繪制一個和狀態(tài)欄一樣高的矩形 
  18.         StatusBarView statusBarView = new StatusBarView(activity); 
  19.         LinearLayout.LayoutParams params = 
  20.                 new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); 
  21.         statusBarView.setLayoutParams(params); 
  22.         statusBarView.setBackgroundColor(calculateStatusColor(color, alpha)); 
  23.         return statusBarView; 

2、Android 5.0(API 21)以上版本

Android 5.0 是一個里程碑式的版本,google 加入了一個比較重要的方法 setStatusBarColor (對應屬性:android:statusBarColor), 通過這個方法,可以很輕松地實現(xiàn)沉浸式狀態(tài)欄。方法如下:

  1. /** 
  2.      * Sets the color of the status bar to {@code color}. 
  3.      * 
  4.      * For this to take effect, 
  5.      * the window must be drawing the system bar backgrounds with 
  6.      * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and 
  7.      * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS} must not be set
  8.      * 
  9.      * If {@code color} is not opaque, consider setting 
  10.      * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and 
  11.      * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}. 
  12.      * <p> 
  13.      * The transitionName for the view background will be "android:status:background"
  14.      * </p> 
  15.      */ 
  16.     public abstract void setStatusBarColor(@ColorInt int color); 

不過,要想這個方法生效,必須還要配合一個 Flag 一起使用,必須設置 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,并且不能設置 FLAG_TRANSLUCENT_STATUS (Android 4.4 才用這個)。

設置了 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 表明 Window 負責系統(tǒng) bar 的 background 繪制,繪制透明背景的系統(tǒng) bar(狀態(tài)欄和導航欄),然后用 getStatusBarColor() 和 getNavigationBarColor() 的顏色填充相應的區(qū)域,實現(xiàn)代碼如下:

  1. getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 
  2. //注意要清除 FLAG_TRANSLUCENT_STATUS flag 
  3. getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 
  4. getWindow().setStatusBarColor(getResources().getColor(android.R.color.holo_red_light)); 

也可以直接在 Theme 中使用,在 vlues-v21 文件夾下添加如下主題:

  1. <style name="MDTheme" parent="Theme.Design.Light.NoActionBar"
  2.         <item name="android:windowTranslucentStatus">false</item> 
  3.         <item name="android:windowDrawsSystemBarBackgrounds">true</item> 
  4.         <item name="android:statusBarColor">@android:color/holo_red_light</item> 
  5. </style> 

如果要讓圖片延申至狀態(tài)欄,只需設置 windowTranslucentStatus,將 statusBarColor 設置為透明,同時設置 DecorView 的 屬性:

  1. getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN |  
  2. View.SYSTEM_UI_FLAG_LAYOUT_STABLE); 

3、Android 6.0 +

其實Android6.0以上的實現(xiàn)方式和Android 5.0 +是一樣,為什么要將它歸為一個單獨重要的階段呢?是因為從Android 6.0(API 23)開始,我們可以改狀態(tài)欄的繪制模式,可以顯示白色或淺黑色的內容和圖標;

使用Android6.0 以上版本沉浸式的時候會遇到一個問題,那就是 Android 系統(tǒng)狀態(tài)欄的字色和圖標顏色為白色,當狀態(tài)欄顏色接近淺色的時候,狀態(tài)欄上的內容就看不清了;

Android 6.0 新添加了一個屬性來解決這個問題,屬性是 SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,可以設置狀態(tài)欄字色和圖標淺黑色。

  1. /** 
  2.      * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 
  3.      * is compatible with light status bar backgrounds. 
  4.      * 
  5.      * <p>For this to take effect, the window must request 
  6.      * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 
  7.      *         FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 
  8.      * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 
  9.      *         FLAG_TRANSLUCENT_STATUS}. 
  10.      * 
  11.      * @see android.R.attr#windowLightStatusBar 
  12.      */ 
  13.     public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 

不過要想這個屬性生效的前提是要先設置了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag ,同時清除了FLAG_TRANSLUCENT_STATUS flag 才會生效。

(1)狀態(tài)欄字體白色

  1. getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);//字體默認白色 
  2. getWindow().setStatusBarColor(android.R.color.transparent);//透明背景 

(2)狀態(tài)欄字體黑色

  1. getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);//黑色字體 
  2. getWindow().setStatusBarColor(android.R.color.transparent);//透明背景 

三、實際沉浸式開發(fā)中的難點分析

1、沉浸式中常用的flag總結

①. View.SYSTEM_UI_FLAG_FULLSCREEN:Activity全屏顯示,且狀態(tài)欄被隱藏覆蓋掉

②.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN:Activity全屏顯示,但狀態(tài)欄不會被隱藏覆蓋,狀態(tài)欄依然可見,

③. View.SYSTEM_UI_FLAG_LAYOUT_STABLE

使用了SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_STABLE,注意兩個Flag必須要結合在一起使用,表示會讓應用的主體內容占用系統(tǒng)狀態(tài)欄的空間

④. View.SYSTEM_UI_FLAG_HIDE_NAVIGATION:隱藏虛擬按鍵(導航欄)。有些手機會用虛擬按鍵來代替物理按鍵。

⑤. View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION:隱藏導航欄 效果同View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

⑥. 有的手機默認全屏顯示,有時需要強制不顯示全屏就用以下flag

不全屏顯示

  1. getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); 

全屏顯示

  1. getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); 

2、狀態(tài)欄字體顏色適配

  1. /*** 
  2.     * 狀態(tài)欄字體適配方案 
  3.     * @param activity 
  4.     * @param dark 
  5.     */ 
  6.    public static void darkMode(Activity activity, boolean dark) { 
  7.        try { 
  8.            if (isFlyme4Later()) { 
  9.                //魅族 
  10.                darkModeForFlyme4(activity.getWindow(), dark); 
  11.            } else if (isMIUI6Later()) { 
  12.                //小米 
  13.                darkModeForMIUI6(activity.getWindow(), dark); 
  14.            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
  15.                //其他通用方案 
  16.                darkModeForM(activity.getWindow(), dark); 
  17.            } 
  18.        } catch (Exception e) { 
  19.        } 
  20.    } 
  21.  /*** 
  22.     * 狀態(tài)欄字體適配方案 
  23.     * @param activity 
  24.     * @param dark 
  25.     */ 
  26.    public static void darkMode(Activity activity, boolean dark) { 
  27.        try { 
  28.            if (isFlyme4Later()) { 
  29.                //魅族 
  30.                darkModeForFlyme4(activity.getWindow(), dark); 
  31.            } else if (isMIUI6Later()) { 
  32.                //小米 
  33.                darkModeForMIUI6(activity.getWindow(), dark); 
  34.            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
  35.                //其他通用方案 
  36.                darkModeForM(activity.getWindow(), dark); 
  37.            } 
  38.        } catch (Exception e) { 
  39.        } 
  40.    } 
  41.   /** 
  42.     * 判斷是否Flyme4以上 
  43.     */ 
  44.    public static boolean isFlyme4Later() { 
  45.        return Build.FINGERPRINT.contains("Flyme_OS_4"
  46.                || Build.VERSION.INCREMENTAL.contains("Flyme_OS_4"
  47.                || Pattern.compile("Flyme OS [4|5]", Pattern.CASE_INSENSITIVE).matcher(Build.DISPLAY).find(); 
  48.    } 
  49.  /** 
  50.     * 判斷是否為MIUI6以上 
  51.     */ 
  52.    @SuppressLint("PrivateApi"
  53.    public static boolean isMIUI6Later() { 
  54.        try { 
  55.            Class<?> clz = Class.forName("android.os.SystemProperties"); 
  56.            Method mtd = clz.getMethod("get", String.class); 
  57.            String val = (String) mtd.invoke(null"ro.miui.ui.version.name"); 
  58.            assert val != null
  59.            val = val.replaceAll("[vV]"""); 
  60.            int version = Integer.parseInt(val); 
  61.            return version >= 6; 
  62.        } catch (Exception e) { 
  63.            return false
  64.        } 
  65.    } 
  66.   /** 
  67.     * android 6.0設置字體顏色 
  68.     */ 
  69.    @RequiresApi(Build.VERSION_CODES.M) 
  70.    private static void darkModeForM(Window window, boolean dark) { 
  71.        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 
  72.        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 
  73.        window.setStatusBarColor(Color.TRANSPARENT); 
  74.        int systemUiVisibility = window.getDecorView().getSystemUiVisibility(); 
  75.        if (dark) { 
  76.            systemUiVisibility |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 
  77.        } else { 
  78.            systemUiVisibility &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 
  79.        } 
  80.        window.getDecorView().setSystemUiVisibility(systemUiVisibility); 
  81.    } 

3、fitsSystemWindows理解和用法

  • 在實現(xiàn)沉浸式狀態(tài)欄時,我們會用到android:fitsSystemWindows="true"這個屬性;
  • 設置了透明狀態(tài)欄(StatusBar)或者導航欄(NavigationBar)之后,activity的內容會延伸至對應的區(qū)域,使得該區(qū)域出現(xiàn)重疊現(xiàn)象,這對內容包含交互控件的情況影響尤其巨大,為了解決這個情況,fitsSystemWindows屬性出現(xiàn)了,我們可以為任何view添加此屬性,設置了該屬性的view的所有padding屬性將失效,并且系統(tǒng)會根據(jù)情況給該view添加paddingTop和paddingBottom(當設置透明狀態(tài)欄時,系統(tǒng)會為該view添加一個值等于狀態(tài)欄高度的paddingTop,當設置了透明導航欄時,系統(tǒng)會為該view添加一個值等于導航欄高度的paddingBottom);
  • 在默認情況下,多個view設置該屬性時,只有最外層的view才會起作用;我們也可以通過覆寫自定義view的一些方法來決定自身的處理,及子view是否有機會截斷并對fitsSystemWindows做出自己的反應,如DrawerLayout、CoordinatorLayout和CollapsingToolbarLayout就使用了自定義fitsSystemWindow(難怪給drawerLayout設置該屬性時和我們理解的行為不一致)
  • 要實現(xiàn)的效果有以下兩種:背景圖片填滿了整個屏幕、狀態(tài)欄和actionBar顏色一致。

我們只需要把內容延伸至狀態(tài)欄和導航欄,然后給根布局設置圖片背景,若需要內容不出現(xiàn)在狀態(tài)欄和導航欄區(qū)域則再添加android:fitsSystemWindows="true"既可

  1. /** 
  2.      * 獲取狀態(tài)欄高度 
  3.      */ 
  4.     public static int getStatusBarHeight(Context context) { 
  5.         int result = 24; 
  6.         int resId = context.getResources().getIdentifier("status_bar_height""dimen""android"); 
  7.         if (resId > 0) { 
  8.             result = context.getResources().getDimensionPixelSize(resId); 
  9.         } else { 
  10.             result = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 
  11.                     result, Resources.getSystem().getDisplayMetrics()); 
  12.         } 
  13.         return result; 
  14.     } 

四、沉浸式輪子方案

其實網上有很多成熟的沉浸式方案,我們也沒有必要封裝,主要是要了解其中的知識點,遇到問題好排查問題

網上的輪子StatusBarUtil

有以下的功能:

1、設置狀態(tài)欄顏色

  1. StatusBarUtil.setColor(Activity activity, int color) 

設置狀態(tài)欄半透明

2、StatusBarUtil.setTranslucent(Activity activity, int statusBarAlpha)

設置狀態(tài)欄全透明

  1. StatusBarUtil.setTransparent(Activity activity) 

3、為包含 DrawerLayout 的界面設置狀態(tài)欄顏色(也可以設置半透明和全透明)

  1. StatusBarUtil.setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, int color) 

4、為使用 ImageView 作為頭部的界面設置狀態(tài)欄透明

  1. StatusBarUtil.setTranslucentForImageView(Activity activity, int statusBarAlpha, View needOffsetView) 

5、在 Fragment 中使用

6、通過傳入 statusBarAlpha 參數(shù),可以改變狀態(tài)欄的透明度值,默認值是112。

總結:

 

這次知識點總結,希望可以給還沒有使用沉浸式的同學一些幫助。如果你已經使用過沉浸式狀態(tài)欄,可以對各個版本實現(xiàn)的原理有一個更深的了解。

 

責任編輯:武曉燕 來源: Android開發(fā)編程
相關推薦

2017-02-17 11:00:57

狀態(tài)欄Android

2016-11-29 11:20:08

Android

2017-12-05 12:44:57

Android沉浸式狀態(tài)欄APP

2022-11-23 14:47:29

北向開發(fā)鴻蒙

2021-09-07 06:40:25

AndroidLiveData原理

2014-06-06 14:03:13

iOS狀態(tài)欄提示控件原理

2021-09-01 06:48:16

AndroidGlide緩存

2021-09-06 13:12:05

前端JavaScript編程

2021-08-05 20:39:34

AndroidKotlinStandard.kt

2021-08-10 20:41:33

AndroidApp流程

2013-07-18 16:09:10

自定義iOS狀態(tài)欄iOS開發(fā)iOS學習

2021-08-17 13:41:11

AndroidView事件

2021-09-02 07:00:01

Glide流程Android

2021-08-25 07:43:17

AndroidSurfaceViewTextureView

2021-08-11 17:15:17

AndroidActivity場景

2015-02-12 14:49:36

CGToast狀態(tài)欄提示Status

2012-12-24 14:42:48

iOS自定義狀態(tài)欄

2021-09-09 06:55:43

AndroidViewDragHel原理

2022-02-22 09:16:41

AndroidWindows狀態(tài)欄

2021-06-15 15:04:38

Android 12安卓通話
點贊
收藏

51CTO技術棧公眾號