这是我参与更文挑战的第1天,活动详情查看:更文挑战
1. 适配介绍
涉及适配的主要是:自定义导航栏(NavigationBar),自定义标签栏(TabBar)以及页面底部的吸底按钮(使用官方组件进行开发,不需要自行适配)。
根据苹果官方的文档,iPhone X顶部状态栏的适配安全区域的高度为44pt,底部操作条区域的高度为34pt(一些系统Bar的默认高度设备可能会变化,建议以官网给出的为准)。
2. 官方文档推荐
官方地址
opendocs.alipay.com/support/01r…
方法
- 在全局store.ts中,全局数据增加一个适配标识isIPhoneX
state: {
// 是不是iphoneX及以上机型
isIPhoneX: false,
}
- 在全局store.ts中,通过 my.getSystemInfo获取设备信息,判断出iPhone设备类型,并存入适配标识isIPhoneX
let cachedSystemInfoPromise: Promise<my.SystemInfo>;
/**
* 带缓存的 getSystemInfo
* 请勿使用同步 getSystemInfoSync
* **无需 catch,报错返回 null**
* 默认 500ms 超时,返回 null
*/
getSystemInfo({ timeout = 500 } = {}): Promise<my.SystemInfo> {
if (cachedSystemInfoPromise) {
return cachedSystemInfoPromise;
}
return cachedSystemInfoPromise = new Promise(resolve => {
setTimeout(() => {
resolve(null);
}, timeout);
my.getSystemInfo({
success(res: my.SystemInfo) {
resolve(res);
},
fail(error) {
console.error('getSystemInfo failed, null will be resolved', error);
resolve(null);
},
});
});
}
async getSystemInfo({ commit }) {
const systemInfo = await getSystemInfo();
const { model = '' } = systemInfo || {};
const iPhoneXSeries = [ 'iPhone10,3', 'iPhone10,6', 'iPhone11,2', 'iPhone11,4', 'iPhone11,6', 'iPhone11,8', 'iPhone12,1', 'iPhone12,3', 'iPhone12,5', 'iPhone13,2' ];
if (iPhoneXSeries.includes(model)) {
commit('setState', {
isIPhoneX: true,
});
}
},
- 在app.ts中,在onLaunch中调用适配逻辑
onLaunch(options: IOptions) {
// 获取设备信息
this.dispatch('getSystemInfo');
}
- 在全局app.less中设置适配样式
.isIphoneX {
padding-bottom: 68rpx !important;
}
- 在页面或者组件中,通过判断全局的适配标识,去动态添加是否有适配样式 ts:
getters: {
isIphoneX: ({ global }) => (global?.isIPhoneX || false),
}
axml:
<view class="container-footer {{ isIphoneX ? 'isIphoneX' : '' }}">
底部
</view>
特征
涉及到js,css判断,繁琐,代码量多
3. 苹果官方推荐
官方地址
Designing Websites for iPhone
安全区域(safe area): 核心内容应该处于Safe area确保不会被设备圆角(corners),传感器外壳(sensor housing,齐刘海) 以及底部小黑条(Home Indicator)遮挡。
env()和constant(): 是IOS11新增特性,Webkit的css函数,用于设定安全区域与边界的距离,有4个预定义变量:
safe-area-inset-left:安全区域距离左边边界的距离,纵向时为0px
safe-area-inset-right:安全区域距离右边边界的距离,纵向时为0px
safe-area-inset-top:安全区域距离顶部边界的距离,纵向时为44px
safe-area-inset-bottom:安全距离底部边界的距离,纵向时为34px
使用前提: env()和constant()函数有个必要的使用前提,H5网页设置viewport-fit=cover的时候才生效,小程序里的viewport-fit默认是cover。
<meta name='viewport' content='initial-scale=1, viewport-fit=cover'>
方法
css适配:
page {
height: calc(96rpx+ constant(safe-area-inset-bottom)); // 兼容 IOS<11.2
height: calc(96rpx + env(safe-area-inset-bottom)); // 兼容 IOS>11.2
padding-bottom: constant(safe-area-inset-bottom); // 兼容 IOS<11.2
padding-bottom: env(safe-area-inset-bottom); // 兼容 IOS>11.2
}
// constant()跟env()需要同时存在,且顺序不能更换,先constant再env
- 因在小程序中用rpx为单位,safe-area-inset-bottom的单位为px,但calc会自动处理rpx与px的单位关系,转为统一的rpx单位。
- 之所以写了constant和env两种,是因为ios11.2版本以后constant废弃,env生效。写2种是兼容所有ios版本 官方自从11.2后废弃constant说明截图如下:
min、max、calc与@supports
主要解决横竖屏兼容:设备横屏竖屏的状态都会导致safe-area-inset-bottom的对象不一致,这时候设置的值就会有问题。 解决方案一(推荐):
@supports(padding: max(0px)) {
.post {
padding-bottom: max(12px, env(safe-area-inset-bottom));
}
}
在上面的例子中:当设备竖屏时,拥有safe-area-inset-bottom,这时候基本上会大于12px,因此取值safe-area-inset-bottom;当横屏时,safe-area-inset-bottom为0,这时候会取默认12px,保证横屏时页面底部不会太贴边。
使用@supports,是因为max不一定在任何地方都支持。min,max这两个函数可以在calc()内部使用,可以相互嵌套,也允许在它们内部使用类似calc()。
解决方案二:也可以使用calc()计算,不管safe-area-inset-bottom有没有,都设置12px的默认值。如下:
.post {
padding-bottom: calc(12px(默认值) + env(safe-area-inset-bottom));
}
@support MDN文档: developer.mozilla.org/zh-CN/docs/… 在古董机(iphone SE 1代,IOS 10.3系统)等不支持constant特性的情况下,可以使用css的@supports的not
.post {
padding-bottom: calc(constant(safe-area-inset-bottom) + 150rpx);
padding-bottom: calc(env(safe-area-inset-bottom) + 150rpx);
}
/* not 表示不支持括号内的属性 */
@supports not(constant(safe-area-inset-bottom)){
.post {
padding-bottom: 150rpx;
}
}
特征
仅使用css代码就可实现Android、iphone各机型的兼容,并支持横屏竖屏的兼容,推荐使用