魅族Flyme7系统刘海屏app适配文档

一, 需求

  1. 竖屏有状态栏时由状态栏调整其布局来适配刘海区
  2. 横屏或竖屏无状态栏时默认情况下由系统平移界面来避开刘海区
  3. 若要在上述状态下, 显示到刘海区域。 则应用需要适配.
11.png
  • 需注意在适配刘海区域时, 在设置中 “显示/隐藏” 开关的不同表现:
    虽然页面适配后允许应用的内容拓展到刘海区域, 但是仍然要注意不要放置关键信息。 因为在"隐藏刘海"开关打开的情况下, 拓展的内容会被裁剪

二, 应用适配方法(广大app开发者通过此方法适配即可)

1. 适配刘海区域

若要在竖屏无状态栏情况下使用刘海区域。 应用可在页面进行如下配置。

// Android P中已增加适配刘海屏的原生接口支持。 设置此方式只在Android P以下版本有效。
if (Build.VERSION.SDK_INT < 28) {
   View decor = getWindow().getDecorView();
   decor.setSystemUiVisibility(decor.getSystemUiVisibility() | 0x00000080);
}
//注1: 此逻辑的关键在于为systemUiFlag添加 0x00000080, 请应用在操作时请不要将此字段覆盖。
//注2:据同事反馈在Android M和L中, setSystemUiVisibility与requestWindowFeature共用时, 
//     需将setSystemUiVisibility置于requestWindowFeature之后, 否则会闪退。

2. 判断是否刘海设备

// 判断刘海设备
boolean fringeDevice = false;
try {
  Class clazz = Class.forName("flyme.config.FlymeFeature");
  Field field = clazz.getDeclaredField("IS_FRINGE_DEVICE");
  fringeDevice = (boolean) field.get(null);
} catch (Exception e) {
  Log.e("ERROR", e.toString());
}

3. 获取刘海区域大小

// 获取刘海高度(51px)
int fringeHeight = 0;
int fhid = getResources().getIdentifier("fringe_height", "dimen", "android");
if (fhid > 0) {
  fringeHeight = getResources().getDimensionPixelSize(fhid);
}
// 获取刘海宽度(534px,)
int fringeWidth = 0;
int fwid = getResources().getIdentifier("fringe_width", "dimen", "android");
if (fwid > 0) {
  fringeWidth = getResources().getDimensionPixelSize(fwid);
}

4. 判断隐藏刘海开关状态

// 判断隐藏刘海开关(默认关)
boolean isFringeHidden = Settings.Global.getInt(getContentResolver(), "mz_fringe_hide",0) == 1;

5. 监听刘海开关状态

Uri uri = Settings.Global.getUriFor("mz_fringe_hide");
getContentResolver().registerContentObserver(uri, false, new ContentObserver(new Handler()) {
    @Override
    public void onChange(boolean selfChange) {
        boolean isHidden = Settings.Global.getInt(getContentResolver(), "mz_fringe_hide",0) == 1;
        //TODO 监听获取
    }
});

三, 系统获取方法

1. 判断是否刘海设备

// 判断刘海设备
boolean fringeDevice = flyme.config.FlymeFeature.IS_FRINGE_DEVICE;

2. 获取刘海区域大小

// 获取刘海高度(51px)
int fringeHeight = getResources().getDimensionPixelSize(com.android.internal.R.dimen.fringe_height);
// 获取刘海宽度(534px,)
int fringeWidth = getResources().getDimensionPixelSize(com.android.internal.R.dimen.fringe_width);

3. 判断隐藏刘海开关状态

// 判断隐藏刘海开关(默认关)
boolean isFringeHidden = Settings.Global.getInt(mContext.getContentResolver(),MzSettings.Global.MZ_FRINGE_HIDE, 0) == 1;

四, 系统弹窗

框架对系统弹窗也做了处理。 但是仅限layer层级低于StatusBar的窗口, 具体参见WindowManagerPolicy.java 的 getWindowLayerFromTypeLw 方法中的定义

1. 处理逻辑

12.png

这里注意与上面不同:我们为系统弹窗赋予了更高的权限, 系统弹窗若做了适配, 则无视隐藏刘海开关状态, 始终按原始方式显示

2. 适配方法

View view = new View(context);
if (Build.VERSION.SDK_INT < 28) {
    view.setSystemUiVisibility( view.getSystemUiVisibility() | 0x00000080);
}
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
windowManager.addView(view, params);

此处需注意对setSystemUiVisibility的设置需位于 addView 之前。 且一经设置, 不容改变

五, 特殊需求

1, 忽略隐藏刘海开关

在我们的原需求中, 如果用户在设置中手动开启了“隐藏刘海”开关。 则无论应用是否(应用二.1中的方法)适配刘海屏, 都会在顶部显示黑色圆角以隐藏刘海。但是在某些重要场景中, 应用希望自行处理隐藏刘海的情况, 如相机, 图库。。

应用可以使用如下方法来屏蔽系统关于刘海开关的相关处理。 (请使用201808241800之后的版本进行验证。 )

if (Build.VERSION.SDK_INT < 28) {
   View decor = getWindow().getDecorView();
   decor.setSystemUiVisibility(decor.getSystemUiVisibility() | 0x00000080 | 0x00000040);
}
// 0x00000040需要与0x00000080配合使用, 单独使用无效。

注意: 为了保证系统功能的一致性, 请谨慎使用此功能

开发者可以购买 魅族X8 来进行问题的验证

https://item.jd.com/100000827661.html

上述文档仅仅针对与Android8.0的机器有效, Android9.0已经官方公开了刘海屏的接口,相关的适配参考如下:

针对当前android 9.0的刘海屏, 有很多应用出现了界面的平移现象. 这主要是由Android P的原生逻辑来控制的. 所以需要应用对刘海屏进行适配. 适配方法如下

一. 原生判断是否刘海屏方式

由于Android P对异型屏各种情况的考虑, 比如有多处异型区域, 异型区域不规则等等情况. 系统中引入了 DisplayCutout 和 LAYOUT_IN_DISPLAY_CUTOUT_MODE 方便应用去适配. 判断方式如下:

DisplayCutout displayCutout = decorView.getRootWindowInsets().getDisplayCutout();
if (displayCutout != null) {
    Log.e("TAG", "安全区域距离屏幕左边的距离 SafeInsetLeft:" + displayCutout.getSafeInsetLeft());
    Log.e("TAG", "安全区域距离屏幕右部的距离 SafeInsetRight:" + displayCutout.getSafeInsetRight());
    Log.e("TAG", "安全区域距离屏幕顶部的距离 SafeInsetTop:" + displayCutout.getSafeInsetTop());
    Log.e("TAG", "安全区域距离屏幕底部的距离 SafeInsetBottom:" + displayCutout.getSafeInsetBottom());
    List<Rect> rects = displayCutout.getBoundingRects();
    if (rects == null || rects.size() == 0) {
        Log.e("TAG", "不是刘海屏");
    } else {
        Log.e("TAG", "刘海屏数量:" + rects.size());
        for (Rect rect : rects) {
            Log.e("TAG", "刘海屏区域:" + rect);
        }
    }
} else {
    Log.e("TAG", "不是刘海屏!!!!!!!!!!!!!!!!!!!!!!");
}

若在onCreate中获取, 请使用decorView.post(new Runnable() { ....})

二. Flyme判断刘海屏方式

鉴于一方面仍然有许多应用反馈按照原生的方式得到为null,另一方面使用原生的判断方式时机可能比较晚,这里提供flyme的一种判定方式


 DisplayManager dy = (DisplayManager) getApplicationContext().getSystemService(Context.DISPLAY_SERVICE);
        Display d = dy.getDisplay(Display.DEFAULT_DISPLAY);
        int FLAG_DISPLAY_CUTOUT = 1 << 29;
        if ((d.getFlags() & FLAG_DISPLAY_CUTOUT) != 0) {
                                    //是刘海屏
        } else {
                                    //不是刘海屏
        }

二. 异型屏适配.

请各应用按需使用设置

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

至于使用各模式的效果, 请查看附件demo

  • 注意: 对于异型屏的处理, 大多数应用可能会用到LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 模式, 但是此模式在demo中顶部会有一个白条(Activity). 这时需要应用对页面进行沉浸式处理.
  • 本文档较简单, 想要详细的介绍可参阅 https://blog.csdn.net/yi_master/article/details/80309757
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355