android全屏透明狀態(tài)欄的坑

零、摘要

Android全屏透明狀態(tài)欄的文章已經(jīng)有不少了,也有開源的庫(kù)甚至,本文著重講具體實(shí)施背后遇到的那些坑。

一、為什么

現(xiàn)有很多app在Android機(jī)器上狀態(tài)欄的體驗(yàn)并不好,有一道灰色的條。比如手機(jī)QQ在7.0 vivo上的效果:


圖1.1

我們期望的效果是:

  1. 全屏,app界面的布局延伸到狀態(tài)欄
  2. 沒有頂部的陰影
  3. 狀態(tài)欄背景色為透明或者跟隨app界面顏色
  4. 狀態(tài)欄字體和icon顏色可以根據(jù)界面顏色深淺設(shè)置為淺或深,以避免都為淺色或深色而看不見狀態(tài)欄字體和icon。
    如下圖所示效果:


    圖1.2

    圖中左邊狀態(tài)欄背景是透明,字體是淺色,右邊狀態(tài)欄背景是白色,字體是深色。

二、怎么做

為了達(dá)到一中所說(shuō)的1,2,3和4的效果,先看下Android在api上的支持。

2.1 Android4.4

可以實(shí)現(xiàn)狀態(tài)欄背景色透明或其它顏色,但是做不到效果中的4。
實(shí)現(xiàn)步驟:

  1. 通過(guò)配置values-19文件夾下的style屬性
<item name="android:windowTranslucentStatus">true</item>

或者activity里設(shè)置

getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  1. 狀態(tài)欄透明后,可以再自己定義一個(gè)狀態(tài)欄高度的view,設(shè)置其顏色就相當(dāng)于設(shè)置狀態(tài)欄背景色了??梢詤⒖计渌鼱顟B(tài)欄的文章,不再贅述。
    這樣得到的效果:


    圖2.1

然而,試了幾款機(jī)器,發(fā)現(xiàn)并不是所有機(jī)型都能達(dá)到這個(gè)效果,比如vivo的機(jī)器上就不行,沒有全屏:


圖2.2

看效果是全屏的flag沒起作用,因?yàn)楣俜轿臋n說(shuō),設(shè)置了WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS flag后,會(huì)自動(dòng)設(shè)置另外兩個(gè)屬性:

When this flag is enabled for a window, it automatically sets the system UI visibility flags SYSTEM_UI_FLAG_LAYOUT_STABLE and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN.

手動(dòng)把這兩個(gè)屬性設(shè)置后,布局倒是延伸到狀態(tài)欄了,不過(guò)狀態(tài)欄也不見直接隱藏了,有興趣的可以研究下vivo的4.4機(jī)器上能不能做到。

再比如三星機(jī)器上,系統(tǒng)會(huì)默認(rèn)給系統(tǒng)狀態(tài)欄加點(diǎn)陰影:


圖2.3

再比如oppo r7的coloros 2.1系統(tǒng)上能達(dá)到理想效果,也有oppo r7效果不行,狀態(tài)欄是黑色,可能和coloros的版本有關(guān)系吧。

注:如果在android高版本設(shè)置了4.4的這個(gè)屬性,通常會(huì)是開篇說(shuō)的手q那種效果。

2.2 Android5.0和Android5.1

可以直接實(shí)現(xiàn)狀態(tài)欄背景顏色,不用像4.4上需要自己去搞自定義view,當(dāng)然也可以給狀態(tài)欄設(shè)置一個(gè)透明顏色,然后繼續(xù)用自定義view的方案也是沒問題的。但是和4.4一樣,沒法改變狀態(tài)欄字體和icon顏色。
按照官方文檔:

Sets the color of the status bar to color. For this to take effect, the window must be drawing the system bar backgrounds with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS and FLAG_TRANSLUCENT_STATUS must not be set.
If color is not opaque, consider setting SYSTEM_UI_FLAG_LAYOUT_STABLE and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN.

代碼如下:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(getResources().getColor(android.R.color.holo_red_light));

如果不是不透明,也就是有透明度的,把這兩個(gè)也設(shè)置上:

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

具體效果和機(jī)型適配不再測(cè)試。。。

2.3 Android6.0及以上

到了這里,終于可以完全實(shí)現(xiàn)我們要的效果了。因?yàn)锳pi23增加了一個(gè)屬性SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,可以設(shè)置狀態(tài)欄字體和icon是深顏色還是淺顏色。設(shè)置狀態(tài)欄背景色的api還是和Android5.0上一樣。代碼差不多就這樣:

if(Build.VERSION.SDK_INT >= LOLLIPOP) {
            int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 
            getWindow().setStatusBarColor(Color.TRANSPARENT); 
            if(Build.VERSION.SDK_INT >= M) {
                uiFlags = setStatusBarDarkFont(uiFlags);
            }
             getWindow().getDecorView().setSystemUiVisibility(uiFlags);
        }

private int setStatusBarDarkFont(int uiFlags) {
        if (isSystemSetDarkFontSupport() && mFontDarkMode) {
            return uiFlags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
        } else {
            return uiFlags;
        }
    }

這樣設(shè)置后我們的app界面就從狀態(tài)欄頂部開始布局了,根據(jù)需要有些界面可以直接在狀態(tài)欄的位置就顯示,有些可能需要從狀態(tài)欄下沿才開始顯示,具體效果可參見圖1.2中的左和右,針對(duì)后者,我們還可以像4.4一樣,自己搞一個(gè)假的view占位,也可以用其它不少的方法,具體可參見這篇文章:
http://www.itdecent.cn/p/2a884e211a62
本文建議還是自己搞一個(gè)假的view占位,原因后面會(huì)說(shuō)。
這樣就萬(wàn)事大吉了?如果是的話那就不叫Android了,接下來(lái)說(shuō)說(shuō)那些坑吧,主要針對(duì)Android6.0及以上的系統(tǒng)。

三、坑

3.1 閃的問題

通過(guò)2.3中的api設(shè)置后,發(fā)現(xiàn)很多機(jī)器在切換activity時(shí),狀態(tài)欄會(huì)閃一下,解決方案,需要在Activity的style屬性里添加:

        <item name="android:windowIsTranslucent">true</item>

可以在values-v23文件夾下加。不過(guò)加了這個(gè)會(huì)有些影響:

  1. 對(duì)activity生命周期的影響,Activity A上啟動(dòng)了一個(gè)加上此屬性的Activity B,A不會(huì)走onStop,當(dāng)B銷毀時(shí),A不會(huì)走onStart。如果基類Activity或某些Activity在onStart里有些特殊邏輯處理需要注意下。
  2. 對(duì)transition動(dòng)畫可能會(huì)有影響,比如我遇到的是通過(guò)ActivityOptionsCompat.makeSceneTransitionAnimation做動(dòng)畫的界面,在onBackPressed activity時(shí)會(huì)黑屏一下,我是在onBackPressed直接finish掉不做動(dòng)畫,不調(diào)super.onBackPressed。

3.2 DialogFragment問題

全屏DialogFragment時(shí),發(fā)現(xiàn)狀態(tài)欄頂部還是和開篇說(shuō)的QQ那樣的效果,代碼里怎么調(diào)都還是那結(jié)果,差點(diǎn)放棄。。最后發(fā)現(xiàn),在布局里調(diào)用就好了,原因就懶得去找了。

<item name="android:windowTranslucentStatus">false</item>
        <item name="android:statusBarColor">@color/thirtyalphablack</item>
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>

再特別提一句,meizu flyme上不要通過(guò)這種方式,否則狀態(tài)欄和布局之間會(huì)有一條灰線,不過(guò)魅族不加這些參數(shù)全屏DialogFragment也顯示正常。

3.3 左右滑動(dòng)問題

2.3中說(shuō)到,盡量自己搞個(gè)占位的view來(lái)讓需要的界面從狀態(tài)欄下面開始展示,這樣一方面是好控制,另一方面是遇到,如果是通過(guò)setStatusBarColor或者設(shè)置ContentView的padding來(lái)的話,左右滑動(dòng)時(shí),狀態(tài)欄不會(huì)跟著走,這樣的效果:


1513524906862.jpg

這個(gè)問題如果不通過(guò)占位方式的話,感覺應(yīng)該也可以解決,有興趣的可以研究下。

3.4 特例品牌魅族

魅族從FlymeOS4就開始提供了設(shè)置狀態(tài)字體深色或淺色的api了,這里建議判斷下是否大于等于Flyme OS4,是的話使用其自己的api,使用系統(tǒng)的反而有問題,好像會(huì)導(dǎo)致切換字體顏色時(shí)閃。

3.5 特例品牌小米

小米也一樣,很早就搞了自己的私有API來(lái)設(shè)置狀態(tài)欄字體顏色深淺,不過(guò)在其開發(fā)版7.7.13后又恢復(fù)到原生api了,私有API沒有了效果。但是miui的開發(fā)版和發(fā)布版并沒有明確的對(duì)應(yīng)關(guān)系,所以系統(tǒng)的和小米的都得調(diào),不過(guò)根據(jù)MIUI9的發(fā)布日志,可以推測(cè)MIUI9以后都是開發(fā)版7.7.13之后了,所以可以判斷下如果是大于等于miui6小于miui9之間,兩種api都調(diào),大于等于miui9的話則只需調(diào)用系統(tǒng)的。參考鏈接:
http://www.miui.com/thread-8946673-1-1.html
摘要:

大家好,在本周開發(fā)版公測(cè)后,MIUI 對(duì)狀態(tài)欄字符顏色的邏輯做了一次調(diào)整:
1. 在 Android 6.0 以前,Android 沒有方法可以實(shí)現(xiàn)「狀態(tài)欄黑色字符」效果,因此 MIUI 自己做了一個(gè)接口;
2. 在 Android 6.0 及以上版本,Android 提供了標(biāo)準(zhǔn)的方法實(shí)現(xiàn)「狀態(tài)欄黑色字符」效果,但這個(gè)方法和 MIUI 的方法產(chǎn)生了沖突,
所以當(dāng)開發(fā)者使用 Android 標(biāo)準(zhǔn)方法時(shí),沒有出現(xiàn)預(yù)期的效果,這給很多開發(fā)者都造成了困擾,尤其是海外開發(fā)者。
基于以上背景,我們決定兼容 Android 的方法,舍棄 MIUI 的自己的實(shí)現(xiàn)方法。這個(gè)改動(dòng)將會(huì)在 7.7.13 公測(cè)開發(fā)版開始生效(內(nèi)測(cè)版本已生效),
之后隨穩(wěn)定版外發(fā)。非常抱歉給各位帶來(lái)麻煩,但長(zhǎng)遠(yuǎn)來(lái)看,兼容 Android 的標(biāo)準(zhǔn),減少了開發(fā)者的適配成本,對(duì)整個(gè) Android 生態(tài)也更為有利。

http://www.miui.com/thread-8944996-1-1.html
摘要

MIUI 9 第一個(gè)內(nèi)測(cè)版本已于7月27日上午10:00進(jìn)行推送。首批適配機(jī)型:小米手機(jī)6、紅米Note 4X-高通版(其他機(jī)型將分批陸續(xù)進(jìn)行內(nèi)測(cè))。
已申請(qǐng) MIUI 9 內(nèi)測(cè)報(bào)名并通過(guò)審核的米粉,請(qǐng)注意閱讀以下升級(jí)方式:
 1. 小米手機(jī)6:7.7.20開發(fā)版/體驗(yàn)版米粉,可通過(guò) OTA 更新增量包方式,升級(jí)至 MIUI 9。
 2. 紅米Note 4X-高通版:7.7.13開發(fā)版、7.7.22體驗(yàn)版,可通過(guò) OTA 更新增量包方式,升級(jí)至 MIUI 9。

3.6 全屏切換問題
切換到全屏?xí)r,如果隱藏狀態(tài)欄了,那么這種情況下就不要調(diào)用上述函數(shù)。

四、總結(jié)

  1. 上述實(shí)現(xiàn)可以放基類Activity的onResume里,然后添加些可以被子類重寫的函數(shù),比如狀態(tài)欄字體顏色深淺,界面展示是可以和狀態(tài)欄重合還是得從狀態(tài)欄下沿開始等。
  2. Android真是坑,API好難用!

五、感謝

最感謝的是這篇文章及其代碼了:
http://www.itdecent.cn/p/2a884e211a62

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,361評(píng)論 25 708
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,748評(píng)論 4 61
  • 1.感賞自己面對(duì)兒子遲遲不起床時(shí),沒有了往日的嘮叨與催促,心態(tài)平和,在老公多次催促中,我淡定地回了句"再給我十分鐘...
    suhui440閱讀 549評(píng)論 0 51
  • 當(dāng)時(shí)太年輕太單純,如今已不復(fù)當(dāng)初了,變成了整日胡言亂語(yǔ)的大寫污,在敢教室里都公然宣布我要睡天下最帥的男人。反正~想...
    呼叫史迪仔閱讀 697評(píng)論 0 0
  • 患者李繼華,男,新莊鎮(zhèn)鹽店人,腰部,右側(cè)臀部,雙側(cè)膝關(guān)節(jié)疼痛近三個(gè)月,影響正常生活。吃藥,電療無(wú)效,經(jīng)鄰居介紹來(lái)我...
    AA老七閱讀 277評(píng)論 0 0

友情鏈接更多精彩內(nèi)容