Android劉海屏適配方案

隨著iPhone X發(fā)布,國內(nèi)一些廠商也推出了劉海屏手機(jī),即將發(fā)布的Android p也提供了對劉海屏的支持外邓。so揩懒,我們的app也要提前做好適配。

什么是劉海屏?

屏幕的正上方居中位置(下圖黑色區(qū)域)會被挖掉一個孔,屏幕被挖掉的區(qū)域無法正常顯示內(nèi)容单旁,這種類型的屏幕就是劉海屏,也有其他叫法:挖孔屏饥伊、凹凸屏等等象浑,這里統(tǒng)一按劉海屏命名。


OPPO R15.png

目前國內(nèi)廠商已經(jīng)推出的劉海屏Android手機(jī)有華為P20 pro琅豆, vivo X21愉豺,OPPO R15。

如果沒有適配劉海屏?xí)惺裁春蠊?

后果一:導(dǎo)航欄中title被遮擋


未適配劉海屏1

后果二:顯示內(nèi)容下移,頭部出現(xiàn)黑條,底部出現(xiàn)遮擋


未適配劉海屏2

如何適配劉海屏?

由于Android p正式版今日剛發(fā)布, 當(dāng)前市面上的Android 劉海屏手機(jī)還不能用Android 官方提供的方案來解決,那怎么辦呢?還好幾個廠商自己給出了適配方案茫因。我們先講理論后上代碼蚪拦,如果您只想要代碼就直接往下翻:

華為P20 pro

華為劉海屏適配官方文檔
華為給出的文檔最為詳細(xì)(業(yè)界良心),P20 pro預(yù)裝系統(tǒng)對未做劉海屏適配處理的app有一定處理,處理邏輯如下

預(yù)處理流程圖

可見冻押,會被華為系統(tǒng)做偏移處理的有2種情況:
1.未設(shè)置meta-data值驰贷,頁面橫屏狀態(tài)
2.未設(shè)置meta-data值,頁面豎屏狀態(tài)洛巢,不顯示狀態(tài)欄
這2種情況都會出現(xiàn)后果二括袒。如果你的app中頁面沒有這兩種情況,例如都是豎屏且顯示狀態(tài)欄稿茉,你就可以淡定地不做處理锹锰。
現(xiàn)在我們知道原因了就可以對癥下藥了,這里給出我推薦的解決方案(官方給出的解決方案不止一種,可以根據(jù)自己的需要采用) 分為4步:
1.配置meta-data
<meta-data android:name="android.notch_support" android:value="true"/>
①對Application生效,意味著該應(yīng)用的所有頁面漓库,系統(tǒng)都不會做豎屏場景的特殊下移或者是橫屏場景的右移特殊處理:
配置在application下

② 對Activity生效恃慧,意味著可以針對單個頁面進(jìn)行劉海屏適配,設(shè)置了該屬性的Activity系統(tǒng)將不會做特殊處理:


配置在Activity下

2.檢測是否存在劉海屏

public static boolean hasNotchInScreen(Context context) {
    boolean ret = false;
    try {
        ClassLoader cl = context.getClassLoader();
        Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
        Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");
        ret = (boolean) get.invoke(HwNotchSizeUtil);
    } catch (ClassNotFoundException e) {
        Log.e("test", "hasNotchInScreen ClassNotFoundException");
    } catch (NoSuchMethodException e) {
        Log.e("test", "hasNotchInScreen NoSuchMethodException");
    } catch (Exception e) {
        Log.e("test", "hasNotchInScreen Exception");
    } finally {
        return ret;
    }
}

3.獲取劉海屏的參數(shù)

public static int[] getNotchSize(Context context) {
    int[] ret = new int[]{0, 0};
    try {
        ClassLoader cl = context.getClassLoader();
        Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
        Method get = HwNotchSizeUtil.getMethod("getNotchSize");
        ret = (int[]) get.invoke(HwNotchSizeUtil);
    } catch (ClassNotFoundException e) {
        Log.e("test", "getNotchSize ClassNotFoundException");
    } catch (NoSuchMethodException e) {
        Log.e("test", "getNotchSize NoSuchMethodException");
    } catch (Exception e) {
        Log.e("test", "getNotchSize Exception");
    } finally {
        return ret;
    }
}

4. UI適配
沒錯,第1步僅僅是告訴EMUI系統(tǒng)不要瞎操作你的頁面米苹,真正適配的活還要你自己干糕伐。
①判斷是否劉海屏,代碼上面給出了
②如果是劉海屏手機(jī)需要應(yīng)用自己調(diào)整布局避開劉海區(qū)蘸嘶,布局原則:保證重要的文字良瞧、圖片和視頻信息陪汽、可點擊的控件和圖標(biāo)還有應(yīng)用彈窗等等布局建議顯示在狀態(tài)欄區(qū)域以下(安全區(qū)域);不重要褥蚯,遮擋不會出現(xiàn)問題的布局可以延伸到狀態(tài)欄區(qū)域(危險區(qū)域)顯示挚冤,按照這種布局原則修改,可以一次修改就能適配所有的劉海屏手機(jī):

UI適配

vivo & OPPO

OPPO劉海屏適配官方文檔
vivo劉海屏適配官方文檔

vivo 和 OPPO官網(wǎng)僅僅給出了適配指導(dǎo)赞庶,沒有給出具體方案训挡,簡單總結(jié)為:
如有是具有劉海屏的手機(jī),豎屏顯示狀態(tài)欄歧强,橫屏不要在危險區(qū)顯示重要信息或者設(shè)置點擊事件澜薄。
那怎么知道是不是劉海屏手機(jī)呢?
OPPO判斷方法:

public static boolean hasNotchInOppo(Context context){
    return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
}

vivo的判斷方法:

public static final int NOTCH_IN_SCREEN_VOIO=0x00000020;//是否有凹槽
public static final int ROUNDED_IN_SCREEN_VOIO=0x00000008;//是否有圓角
public static boolean hasNotchInScreenAtVoio(Context context){
    boolean ret = false;
    try {
        ClassLoader cl = context.getClassLoader();
        Class FtFeature = cl.loadClass("com.util.FtFeature");
        Method get = FtFeature.getMethod("isFeatureSupport",int.class);
        ret = (boolean) get.invoke(FtFeature,NOTCH_IN_SCREEN_VOIO);

    } catch (ClassNotFoundException e)
    { Log.e("test", "hasNotchInScreen ClassNotFoundException"); }
    catch (NoSuchMethodException e)
    { Log.e("test", "hasNotchInScreen NoSuchMethodException"); }
    catch (Exception e)
    { Log.e("test", "hasNotchInScreen Exception"); }
    finally
    { return ret; }
}

例如圖一是在OPPO R15上出現(xiàn)的title被遮擋,顯示狀態(tài)欄后顯示效果如下:


顯示狀態(tài)欄后

以上所講的是各廠商提供的解決方案, 那么google官方對劉海屏做了什么樣的支持呢?

google官方劉海屏適配方案
google從Android P開始為劉海屏提供支持摊册,目前提供了一個類和三種模式:
一個類
The new DisplayCutout class lets you find out the location and shape of the non-functional areas where content shouldn't be displayed. To determine the existence and placement of these cutout areas, use thegetDisplayCutout() method
就是說可以用DisplayCutout這個類找出劉海(cutout)的位置和形狀肤京,調(diào)用getDisplayCutout()這個方法可以獲取劉海(cutout)的位置和區(qū)域,我們看看這個類提供了什么方法:

DisplayCutout提供的方法.png

所以我們可用這個類判斷是否有劉海的存在以及劉海的位置

DisplayCutout cutout = mContext.getDisplayCutout();

三種模式
A new window layout attribute, layoutInDisplayCutoutMode, allows your app to lay out its content around a device's cutouts. You can set this attribute to one of the following values:

  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
    第一種模式:
    LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT : 僅僅當(dāng)系統(tǒng)提供的bar完全包含了劉海區(qū)時才允許window擴(kuò)展到劉海區(qū),否則window不會和劉海區(qū)重疊
    第二種模式:
    LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES :允許window擴(kuò)展到劉海區(qū)(原文說的是短邊的劉海區(qū), 目前有劉海的手機(jī)都在短邊,所以就不糾結(jié)了)
    第三種模式:
    LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER: 不允許window擴(kuò)展到劉海區(qū)

我們可以設(shè)置是否允許window擴(kuò)展到劉海區(qū)

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

例如一個有狀態(tài)欄的頁面, 我們可以這樣適配:

DisplayCutout cutout = getDisplayCutout();
if(cutout != null){
  WindowManager.LayoutParams lp =getWindow().getAttributes();  
  lp.layoutInDisplayCutoutMode=WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;  
  getWindow().setAttributes(lp);
}

如果覺得有幫助, 點個贊再走可好啊~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茅特,一起剝皮案震驚了整個濱河市忘分,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌白修,老刑警劉巖妒峦,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異兵睛,居然都是意外死亡肯骇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門卤恳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來累盗,“玉大人,你說我怎么就攤上這事突琳∪粽” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵拆融,是天一觀的道長蠢琳。 經(jīng)常有香客問我,道長镜豹,這世上最難降的妖魔是什么傲须? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮趟脂,結(jié)果婚禮上泰讽,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好已卸,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布佛玄。 她就那樣靜靜地躺著,像睡著了一般累澡。 火紅的嫁衣襯著肌膚如雪梦抢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天愧哟,我揣著相機(jī)與錄音奥吩,去河邊找鬼。 笑死蕊梧,一個胖子當(dāng)著我的面吹牛霞赫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播肥矢,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼绩脆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了橄抹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤惕味,失蹤者是張志新(化名)和其女友劉穎楼誓,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體名挥,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡疟羹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了禀倔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榄融。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖救湖,靈堂內(nèi)的尸體忽然破棺而出愧杯,到底是詐尸還是另有隱情,我是刑警寧澤鞋既,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布力九,位于F島的核電站,受9級特大地震影響邑闺,放射性物質(zhì)發(fā)生泄漏跌前。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一陡舅、第九天 我趴在偏房一處隱蔽的房頂上張望抵乓。 院中可真熱鬧,春花似錦、人聲如沸灾炭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咆贬。三九已至败徊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掏缎,已是汗流浹背皱蹦。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留眷蜈,地道東北人沪哺。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像酌儒,于是被迫代替她去往敵國和親辜妓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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