沉浸式狀態欄解決方案

前言

沉浸式(透明)狀態欄是Android4.4及以後的版本出現的,其可以通過改變狀態欄的顏色/透明度實現與activity的聯動效果,淘寶/京東/qq朋友圈等均實現了沉浸式狀態欄的效果.

這裏一定要提一下StatusBarUtil,此項目爲朋友推薦用來參考的項目,本着不重複造輪子的原則,本想着拿來就用,結果:
1. demo在三星note4上面直接就安裝失敗?API21的也會失敗?
2. 爲了使用方便而犧牲了針對性,導致每個方面的使用都很不盡如人意.
3. 項目有着5000+的star,本以爲是個好項目,然而評論區大量的意見和BUG作者視而不見?這5000+是刷出來的?
4. 最重要一點,該項目的狀態欄一旦設置爲透明,那麼底部的虛擬按鍵也會是透明,這就造成了,類似於京東,QQ等底部有tab的頁面直接無法使用.無法僅僅設置狀態欄透明.這麼重要的功能沒有考慮到?
5. 最讓我氣憤的一點:網上有關沉浸式狀態欄的文章,要麼特別簡單,要麼直接抄襲StatusBarUtil,國內抄襲成風?腦子呢?浪費時間

API 19 及以上

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

通用方法,直接設置Windows窗口半透明/透明/漸變式透明
透明效果隨系統改變

經測試
在三星note4是漸變式透明
小米note3手機全透明
魅族MX4半透明

此時activity主視圖居於狀態欄下方,狀態欄浮於視圖上方.此時有Z軸效果

API 21及以上

設置顏色的API只有在21及以上纔有.但是設置顏色和狀態欄透明的FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS不能共存

Step1

/**
  * Flag indicating that this Window is responsible for drawing the background for the
  * system bars. If set, the system bars are drawn with a transparent background and the
  * corresponding areas in this window are filled with the colors specified in
  * {@link Window#getStatusBarColor()} and {@link Window#getNavigationBarColor()}.
  */
public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;

首先添加Flag,該flag表示可以對狀態欄設置顏色,默認爲全透明

Step2

/**
  * Window flag: request a translucent status bar with minimal system-provided
  * background protection.
  * <p>When this flag is enabled for a window, it automatically sets
  * the system UI visibility flags {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
  * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.</p>
  */
 public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;

移除此Flag,由文檔可知此Flag用於設置狀態欄透明,並且背景由系統提供.該FlagFLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS不能共存.

如果不再進行其他的設置,僅設置狀態欄顏色的話,那麼這就是僞沉浸式狀態欄,此時視圖未延伸至狀態欄下方,未出現Z軸的層次效果.通過顏色的視覺效果營造沉浸式狀態欄的感覺.

如果設置此Flag會默認設置系統UISYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,即主視圖佔據全屏,此時主視圖會延伸至狀態欄下方,後文再進行探討.

Step3

網上一直流傳一個說法(百度搜索到的’抄襲者’們):要麼使用系統的默認透明,要麼只能設置顏色,無法把視圖延伸至狀態欄下方.你們都是豬嗎,沒有解決方案的話淘寶,京東,QQ是怎麼做的?

以下爲解決方法1:
StatusBarUtil直接添加了一個Flag

activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);

雖然狀態欄透明和設置狀態欄顏色不能共存,那麼可以設置虛擬鍵透明啊,這是個曲線救國的方法,比較有趣的是,該Flag不僅可以使虛擬鍵透明,同時可以使狀態欄透明.該方法同時也是StatusBarUtil整個項目中的狀態欄透明方法.
缺陷:無法單獨設置狀態欄透明,底部虛擬鍵不透明.對於部分佈局不夠友好

思路:
之前我也一直在糾結這個問題要怎麼解決,一直在想,decor怎麼就不能有個單獨設置狀態欄的方法呢,很遺憾,事實上沒有這種方法,那麼爲了所有設備顯示一致的效果,只能設置狀態欄和全透明瞭.檢測虛擬鍵是否啓用,去預留下邊距進行曲線救國

結果:對於小米全面屏,檢測虛擬鍵一直返回true,並且由於虛擬鍵透明,那麼開啓虛擬按鍵時將會模糊不清,失敗.

於是繼續查找官方文檔,有了完美解決方案

解決方案2:
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
沒錯,上文提到的SYSTEM_UI_FLAG_LAYOUT_FULLSCREENFlag.

之前一直被decorview的flag所侷限,一直認爲會有能解決的Flag可以使用.後面再閱讀源碼時,發現在設置Flag時都會自動去設置系統UI的屬性,由此找到切入點.

SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN屬性可以使activity所填充的視圖可以延伸至statusbar下方,形成Z軸的重疊效果,並且不會延伸至虛擬鍵下方,完美解決問題.
當然同樣也有屬性可以使視圖延伸至虛擬鍵下方,有興趣的讀者可以自行查閱文檔

Step4

此時已經完成沉浸狀態欄效果,但是大家會發現部分視圖元素會與狀態欄的圖標重疊,網上很多的文章,包括StatusBarUtil的作者也是通過在狀態欄下方添加登高的色塊來避免重疊,當頂部視圖是圖片時就不用色塊,讓圖片自然在狀態欄下方顯示,那麼就會出現以下問題:
1. 當頂部有多個視圖重疊,同時需要延伸至頂部怎呢辦
2. 當頂部視圖顏色會動態發生變化怎麼辦.
3. 當頂部視圖是圖片時,同時不希望發生拉伸時怎麼辦
4. 當頂部視圖是圖片背景,內部有大量的UI控件,無法用色塊擴展怎麼辦

這時,色塊的作用侷限性就被放大了,我所採用的方法是,增大高度,添加padding,動態更改margin進行適配.以下爲通用的方法步驟:
1. 高度在原基礎上增加50dp;
2. 上邊距在原基礎上增加50dp;
3. 測量狀態欄高度.
4. marginTop的值爲負數,其絕對值爲:50dp對應的px值減去狀態欄的高度

注意:
高度增加50dp爲較爲穩妥的寫法,在劉海屏出現之前,高度爲固定25dp,在使用小米8後發現這個高度僅僅填充了大半,此時需要填充較爲充足的預留高度.當然直接寫死增大50dp的高度可能仍然會有些拉伸,大家可以動態去計算高度
marginTop設置爲負數相信大家都有過類似操作的經歷,比如下拉刷新,比如網頁裏面通過margin進行定位等等,我也是從這裏得到的靈感.
高度需要設置爲固定值,無論是在xml設置還是通過params設置,否則會導致部分機型出現過度拉伸

至此已完成沉浸式狀態欄,至於其他的擴展功能需要大家發散思維.這裏僅提供解決方案和思路

感想

  1. 網上代碼良莠不齊,很難獲取到想要到答案.
  2. 抄襲成風
  3. 閱讀源碼的重要性
  4. 開發功能應基於需求而不是基於通用性.即使通用性再好,場景覆蓋的那麼少又有什麼用.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章