Android 9.0 適配——劉海屏

前言

劉海屏是指某些設備顯示屏上的一個區(qū)域延伸到顯示面,這樣既能為用戶提供全面屏體驗,又能為設備正面的重要傳感器留出空間。Android在搭載Android 9.0/P(API 級別 28)及更高版本的設備上正式支持劉海屏缔刹。設備制造商也可以選擇在搭載Android 8.1或更低版本的設備上支持劉海屏。

官方地址:

https://developer.android.com/guide/topics/display-cutout

Android 9.0及以上:

layoutInDisplayCutoutMode

Android允許控制是否在劉海區(qū)域內(nèi)顯示內(nèi)容魄梯。窗口布局屬性layoutInDisplayCutoutMode控制內(nèi)容如何呈現(xiàn)在劉海區(qū)域中:

  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT:這是默認行為桨螺,如上所述。在豎屏模式下酿秸,內(nèi)容會呈現(xiàn)到劉海區(qū)域中灭翔;但在橫屏模式下,內(nèi)容會顯示黑邊辣苏。
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES:在豎屏模式和橫屏模式下肝箱,內(nèi)容都會呈現(xiàn)到劉海區(qū)域中。
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER:內(nèi)容從不呈現(xiàn)到劉海區(qū)域中稀蟋。
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS:內(nèi)容始終呈現(xiàn)到劉海區(qū)域中煌张。
DisplayCutout
  • getBoundingRects():返回Rects的列表,每個Rects都是顯示屏上非功能區(qū)域的邊界矩形退客。
  • getSafeInsetLeft():返回安全區(qū)域距離屏幕左邊的距離专控,單位是px。
  • getSafeInsetRight():返回安全區(qū)域距離屏幕右邊的距離兜叨,單位是px躏率。
  • getSafeInsetTop():返回安全區(qū)域距離屏幕頂部的距離,單位是px茫藏。
  • getSafeInsetBottom():返回安全區(qū)域距離屏幕底部的距離误趴,單位是px。
通過代碼演示不同窗口及l(fā)ayoutInDisplayCutoutMode的區(qū)別:
主題

將主題修改成不帶ActionBar的樣式

<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.PBangScreenDemo" parent="Theme.MaterialComponents.DayNight.NoActionBar">
        XXXXX
    </style>
</resources>
布局

將文本頂在布局的左上角务傲,方便演示

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_orange_dark"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
代碼

檢測是否是劉海屏凉当,如果存在劉海屏枣申,則給布局增加一個PaddingTop

    @RequiresApi(api = Build.VERSION_CODES.P)
    private void detect() {
        final View decorView = getWindow().getDecorView();
        decorView.post(new Runnable() {
            @Override
            public void run() {
                WindowInsets rootWindowInsets = decorView.getRootWindowInsets();
                if (rootWindowInsets == null) {
                    return;
                }
                DisplayCutout displayCutout = rootWindowInsets.getDisplayCutout();
                if (displayCutout == null) {
                    return;
                }
                Log.e("yzt", "安全區(qū)域距離屏幕左邊的距離>>>" + displayCutout.getSafeInsetLeft());
                Log.e("yzt", "安全區(qū)域距離屏幕右部的距離>>>" + displayCutout.getSafeInsetRight());
                Log.e("yzt", "安全區(qū)域距離屏幕頂部的距離>>>" + displayCutout.getSafeInsetTop());
                Log.e("yzt", "安全區(qū)域距離屏幕底部的距離>>>" + displayCutout.getSafeInsetBottom());
                List<Rect> rects = displayCutout.getBoundingRects();
                if (rects == null || rects.size() == 0) {
                    Log.e("yzt", "不是劉海屏");
                } else {
                    Log.e("yzt", "劉海屏數(shù)量>>>" + rects.size());
                    for (Rect rect : rects) {
                        Log.e("yzt", "劉海屏區(qū)域>>>" + rect);
                    }
                    layout.setPadding(0, displayCutout.getSafeInsetTop(), 0, 0);
                }
            }
        });
    }
全屏情況

設置全屏,寫在setContentView()之前

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

設置layoutInDisplayCutoutMode

        WindowManager.LayoutParams lp = getWindow().getAttributes();
        lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_XXXXX;
        getWindow().setAttributes(lp);

LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT模式


1.jpg

LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES模式


2.jpg

LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER模式
3.jpg

LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS模式


4.jpg
透明狀態(tài)欄情況
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT模式


5.jpg

LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES模式


6.jpg

LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER模式
7.jpg

LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS模式


8.jpg
可以看出當劉海區(qū)域完全在系統(tǒng)的狀態(tài)欄時看杭,LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT的顯示效果與LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES一致忠藤。
完整代碼
public class MainActivity extends AppCompatActivity {

    private View layout;

    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
//        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        setContentView(R.layout.activity_main);
        WindowManager.LayoutParams lp = getWindow().getAttributes();
        //在豎屏模式下,內(nèi)容會呈現(xiàn)到劉海區(qū)域中泊窘;但在橫屏模式下熄驼,內(nèi)容會顯示黑邊。
//        lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
        //在豎屏模式和橫屏模式下烘豹,內(nèi)容都會呈現(xiàn)到劉海區(qū)域中瓜贾。
        lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
        //內(nèi)容從不呈現(xiàn)到劉海區(qū)域中。
//        lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
        //內(nèi)容始終呈現(xiàn)到劉海區(qū)域中携悯。
//        lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        getWindow().setAttributes(lp);
        layout = findViewById(R.id.layout);
        detect();
    }

    @RequiresApi(api = Build.VERSION_CODES.P)
    private void detect() {
        final View decorView = getWindow().getDecorView();
        decorView.post(new Runnable() {
            @Override
            public void run() {
                WindowInsets rootWindowInsets = decorView.getRootWindowInsets();
                if (rootWindowInsets == null) {
                    return;
                }
                DisplayCutout displayCutout = rootWindowInsets.getDisplayCutout();
                if (displayCutout == null) {
                    return;
                }
                Log.e("yzt", "安全區(qū)域距離屏幕左邊的距離>>>" + displayCutout.getSafeInsetLeft());
                Log.e("yzt", "安全區(qū)域距離屏幕右部的距離>>>" + displayCutout.getSafeInsetRight());
                Log.e("yzt", "安全區(qū)域距離屏幕頂部的距離>>>" + displayCutout.getSafeInsetTop());
                Log.e("yzt", "安全區(qū)域距離屏幕底部的距離>>>" + displayCutout.getSafeInsetBottom());
                List<Rect> rects = displayCutout.getBoundingRects();
                if (rects == null || rects.size() == 0) {
                    Log.e("yzt", "不是劉海屏");
                } else {
                    Log.e("yzt", "劉海屏數(shù)量>>>" + rects.size());
                    for (Rect rect : rects) {
                        Log.e("yzt", "劉海屏區(qū)域>>>" + rect);
                    }
                    layout.setPadding(0, displayCutout.getSafeInsetTop(), 0, 0);
                }
            }
        });
    }

}

Android 9.0以下

上面是Android P才有的解決方案祭芦。然而國產(chǎn)廠商在Android P之前(基本都是Android O)就用上了高檔大氣上檔次的劉海屏,所以憔鬼,這也造就了各大廠商在Android P之前的解決方案百花齊放龟劲。這里不詳細介紹。

結(jié)尾

核心思路就是判斷是否帶有劉海屏轴或,根據(jù)自己的項目判斷窗口的情況昌跌,再去決定是否需要做適配,如果需要適配再去根據(jù)實際的設計要求做適配照雁。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蚕愤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子饺蚊,更是在濱河造成了極大的恐慌萍诱,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件污呼,死亡現(xiàn)場離奇詭異裕坊,居然都是意外死亡,警方通過查閱死者的電腦和手機燕酷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門籍凝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人苗缩,你說我怎么就攤上這事静浴。” “怎么了挤渐?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長双絮。 經(jīng)常有香客問我浴麻,道長得问,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任软免,我火速辦了婚禮宫纬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘膏萧。我一直安慰自己漓骚,他們只是感情好,可當我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布榛泛。 她就那樣靜靜地躺著蝌蹂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪曹锨。 梳的紋絲不亂的頭發(fā)上孤个,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機與錄音沛简,去河邊找鬼齐鲤。 笑死,一個胖子當著我的面吹牛椒楣,可吹牛的內(nèi)容都是我干的给郊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捧灰,長吁一口氣:“原來是場噩夢啊……” “哼淆九!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起凤壁,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤吩屹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拧抖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體煤搜,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年唧席,在試婚紗的時候發(fā)現(xiàn)自己被綠了擦盾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡淌哟,死狀恐怖迹卢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情徒仓,我是刑警寧澤腐碱,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響症见,放射性物質(zhì)發(fā)生泄漏喂走。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一谋作、第九天 我趴在偏房一處隱蔽的房頂上張望芋肠。 院中可真熱鬧,春花似錦遵蚜、人聲如沸帖池。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睡汹。三九已至,卻和暖如春攒钳,著一層夾襖步出監(jiān)牢的瞬間帮孔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工不撑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留文兢,地道東北人。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓焕檬,卻偏偏與公主長得像姆坚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子实愚,可洞房花燭夜當晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容