ios 刘海屏,灵动岛的适配以及遇到一些坑点

这篇具有很好参考价值的文章主要介绍了ios 刘海屏,灵动岛的适配以及遇到一些坑点。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

最近再改公司内部移动端 ios 安全区域适配的问题,所谓知己知彼百战百胜,所以深入的学习了一下 安全区域适配有关的知识

问题表象

  • 头部标题区域被灵动岛遮挡,标题被遮挡,返回按钮点不到

antdesignmobile ios刘海屏适配,ios,javascript,前端

  • 底部被遮挡

antdesignmobile ios刘海屏适配,ios,javascript,前端

原因

看一下官方对安全区域[1]的定义。

视图中未被导航栏、选项卡栏、工具栏或视图控制器可能提供的其他视图覆盖的区域。

看一下官方的图就能明白了,蓝色区域是安全区域,白色区域是可能覆盖安全区域的其他视图范围。也就是说,我们要做好适配,必须保证页面可视、可操作区域是在安全区域内。

antdesignmobile ios刘海屏适配,ios,javascript,前端

第一次提出这个概念是 iOS11iPhoneX 机型发布的时候。从 iPhoneX 开始推出了刘海屏,从 iPhone 14 Pro 开始推出了灵动岛。后面的讨论,均以 iPhoneX 机型为例。

处理方案

其实处理方案还是很简单的,将 viewport-fit 指定为cover,这样我们就可以使用 env()constant()这两个函数在css中获取到安全区域的值了,获取到值之后处理对应的间距就可以了。

但是使用的过程中多多少少还是有一些坑点的,下面我来分享一些。

viewport-fit

iOS11 新增特性,苹果公司为了适配 iPhoneX 对现有 viewport meta 标签做了一个扩展,新增viewport-fit属性,用于设置网页在可视窗口的布局方式,可设置三个值:

  • contain:可视窗口完全包含网页内容(左图)

  • cover:网页内容完全覆盖可视窗口(右图)

  • auto:默认值,此值不影响初始布局视图端口,并且整个 web 页面都是可查看的。

containcover 具体区别如下图:

antdesignmobile ios刘海屏适配,ios,javascript,前端

注意:网页的默认值是 viewport-fit=contain,需要适配 iPhoneX 必须设置 viewport-fit=cover,这是适配的关键步骤

<meta name="viewport" content="xxx(你们之前的viewport属性值),viewport-fit=cover" />


<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />

更详细说明,参考文档: viewport-fit-descriptor[2]

坑点 1

viewport-fitcontain 修改成 cover 之后,页面可能会出现白边~~(你要是问为啥,就说明你 viewport-fit 干啥用的没看懂 (ಥ_ಥ))~~,处理方案也很简单,可以给整个页面添加一个页面主题色的背景色,如下图。

antdesignmobile ios刘海屏适配,ios,javascript,前端

env() 和 constant()

iOS11 新增特性,Webkit 的一个 CSS 函数,用于设定安全区域与边界的距离,有四个预定义的变量:

  • safe-area-inset-top:安全区域距离顶部边界距离

  • safe-area-inset-bottom:安全区域距离底部边界距离

  • safe-area-inset-left:安全区域距离左边边界距离

  • safe-area-inset-right:安全区域距离右边边界距离

有一点要注意,在 IOS11.2 系统以前,可以使用 constant()函数,但是在 IOS11.2 系统以后,这个函数就被废弃了,被 env()函数替代了。所以我们在做屏幕适配时,需要这样写:

.footer {
  padding-bottom: constant(safe-area-inset-bottom); // 兼容 IOS 版本 < 11.2
  padding-bottom: env(safe-area-inset-bottom); // 兼容 IOS 版本 >= 11.2
}

并且env()constant()需要同时存在,而且顺序不能换。

使用@supports 一点点的优化

如果我们想只有在需要适配的机型上才适配的时候,我们可以使用 css @supports 语法,检测到这两个变量存在的时候,@supports 内写的 css样式才会被应用。

@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {
  .footer {
    margin-bottom: constant(safe-area-inset-bottom);
    margin-bottom: env(safe-area-inset-bottom);
  }
}

如何优雅的在 js 中获取到这些变量

很多时候,我们会用 JS 做一些效果,比如页面的头部滚动到一定程度的时候需要固定在页面顶上。这个时候就不得不使用 JS 获取到安全区域的值,去适配这个定位的元素。那么现在的问题就变成了,怎么优雅的在 JS 中获取到 safe-area-inset-xxx的值。

其实原理很简单,核心上就是 safe-area-inset-xxx 其实就是苹果为我们注入的 css 变量,我们可以自定义 css 变量,让后使用 JS 获取自定义的 css 变量。

看一段成熟的代码:

function insertSafeAreaCSSVarEl() {
  const cssVarStyleElVer = 1;
  const cssVarStyleElId = 'beisen_mobile_utils_safe_area_vars';
  const existedEl = document.getElementById(cssVarStyleElId);
  if (existedEl) {
    
    const existedVer = parseInt(existedEl.dataset.version || '0');
    if (existedVer >= cssVarStyleElVer) {
      
      return;
    }
    
    existedEl.parentElement?.removeChild(existedEl);
  }
  
  const el = document.createElement('style');
  el.setAttribute('id', cssVarStyleElId);
  el.dataset.version = String(cssVarStyleElVer);
  el.innerHTML = `
:root {
--yl-sat: constant(safe-area-inset-top);
--yl-sat: env(safe-area-inset-top);
--yl-sar: constant(safe-area-inset-right);
--yl-sar: env(safe-area-inset-right);
--yl-sab: constant(safe-area-inset-bottom);
--yl-sab: env(safe-area-inset-bottom);
--yl-sal: constant(safe-area-inset-left);
--yl-sal: env(safe-area-inset-left);
}`;
  document.head.append(el);
}

function parseRootPropertyValue(key) {
  let str = getComputedStyle(document.documentElement).getPropertyValue(key);
  str = str.replace('px', '');
  const n = parseInt(str) || 0;
  return n;
}


 * 获取SafeArea的尺寸。
 */
function getSafeAreaSize() {
  insertSafeAreaCSSVarEl(); 
  return {
    top: parseRootPropertyValue('--yl-sat'),
    right: parseRootPropertyValue('--yl-sar'),
    bottom: parseRootPropertyValue('--yl-sab'),
    left: parseRootPropertyValue('--yl-sal'),
  };
}

核心点是 往 :root 中插入了一些自定义的 css 变量。

坑点 2

上面提到的 getSafeAreaSize 方法有点弊端,我们是主动的往 html 上插入了一个style标签,经过测试,在插入标签的时候,env(safe-area-inset-xxx) 值是空的,等到下一帧渲染的时候才能拿到最新的值。就是说我们第一次获取值的时候是有一定的延迟

这个问题有两个解决方案:

  • 一个是 往 :root 中插入变量的过程放到html页面中,我们请求回来的html文件中就有这些变量了,那我们JS中只需要获取就可以了,是在不行也可以放到 index.css中,初始化样式的时候可以往 :root或者body中加自定义的css变量。

  • 第二个是我们要用之前,提前的执行一下 getSafeAreaSize() 方法。比如在组件的 useLayoutEffect 这个hooks中执行一下(我们是因为有历史原因,没有采用第一种方案,但实际上第一种方案的成本几乎没有)。

坑点 3

虽然说苹果会为我们注入 safe-area-inset-xxx变量到浏览器中,但是这玩意完全是一个黑盒,经过测试发现他是在需要注入的时候才会注入。

那什么叫做 需要注入的时候才会注入呢?

写下如下代码

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, minimum-scale=1, maximum-scale=1.0, user-scalable=0" />

    <style>
      #test123 {
        background: red;
        width: 100px;
        height: 100px;
      }
    </style>
    <script>
      function getSafeAreaSize() {
        
      }
      getSafeAreaSize(); 
    </script>
  </head>
  <body>
    <div id="test123"></div>

    <script>
      const el = document.getElementById('test123');
      setTimeout(() => {
        
        el.innerText = JSON.stringify(getSafeAreaSize());
      }, 20);
    </script>
  </body>
</html>

OK,上面的代码起个本地服务(可以用 Live Server 插件),用手机访问(同一个 WiFi,用 ip+端口访问)一下。

Safari 浏览器的表象如下:

antdesignmobile ios刘海屏适配,ios,javascript,前端

我们发现明明是 14Pro 的机型,但是 top 和 bottom 的值是 0。

再看一下微信内置浏览器打开是什么样的。

antdesignmobile ios刘海屏适配,ios,javascript,前端

我们发现 bottom 有值,但是 top 却没有值。

综上可以看出,我们的页面存在的区域被操作栏或者底部小黑条遮挡了的时候,safe-area-inset-xxx才会有值,也就是我上面说的 需要注入的时候才会注入

坑点 4

还是微信内置浏览器,他有一个特性,就是 A 页面跳转到 B 页面的时候,B 页面下面会自带一个底部操作区。如图

antdesignmobile ios刘海屏适配,ios,javascript,前端

出现了底部操作区的时候,我们的页面就不需要再做适配了

适配的伪代码如下

let safeBottom = 0;
if (isWechat && !isWechatWork) {
  safeBottom = window.history.length > 1 ? 0 : 'env(safe-area-inset-bottom)';
}

处理方案 2-不推荐

在学习的过程中发现我们的系统里面还有如下的实现,使用 @media检查当前屏幕的分辨率信息,来判断对应的机型,然后做相关的适配。只做一种学习了解,不推荐这个方案实现。文章来源地址https://www.toymoban.com/news/detail-764716.html

@media only screen and (min-device-width: 375px) and (max-device-height: 812px) and (-webkit-device-pixel-ratio: 3) {
  
}

@media only screen and (min-device-width: 390px) and (max-device-height: 844px) and (-webkit-device-pixel-ratio: 3) {
  
}

@media only screen and (min-device-width: 414px) and (max-device-height: 896px) and (-webkit-device-pixel-ratio: 2) {
  
}

@media only screen and (min-device-width: 414px) and (max-device-height: 896px) and (-webkit-device-pixel-ratio: 3) {
  
}

@media only screen and (min-device-width: 428px) and (max-device-height: 926px) and (-webkit-device-pixel-ratio: 3) {
  
}

到了这里,关于ios 刘海屏,灵动岛的适配以及遇到一些坑点的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端Vue自定义tabbar底部tabbar凸起tabbar兼容苹果刘海屏小程序和APP

    前端Vue组件化开发:自定义tabbar组件的设计与实现  兼容苹果刘海屏小程序和APP 摘要: 随着前端开发技术的不断发展,组件化开发成为了提高开发效率和降低维护成本的有效手段。本文将介绍一款基于Vue的前端自定义tabbar组件的设计与实现,该组件具有单独开发、单独维护

    2024年02月11日
    浏览(53)
  • iOS16新特性 | 灵动岛适配开发与到家业务场景结合的探索实践

    作者:京东零售 姜海 灵动岛是苹果在iPhone 14 Pro和iPhone 14 Pro Max上首次提出的全新UI交互形式,创新性的让虚拟软件和硬件的交互变得更为流畅。当有来电、短信等通知时,灵动岛会变化形态,以便让用户能够更直观地接收到这些信息。 而在用户使用一些应用App,比如音乐,

    2023年04月12日
    浏览(26)
  • iOS 17新特性以及适配细节汇总

    1、UIScrollView 增加了属性 allowsKeyboardScrolling 表示是否根据连接的物理键盘的方向键而滚动。 2、applicationIconBadgeNumber UIApplication 的 applicationIconBadgeNumber 属性被废弃,建议使用 UNUserNotificationCenter.current().setBadgeCount() 方法。 3、UIDocumentViewController 新增视图控制器,用于显示与管理

    2024年02月08日
    浏览(25)
  • 如何安装wsl以及安装时遇到的一些问题

    首先我安装wsl是参考这篇文章:Windows安装WSL详解 讲得挺具体,如果安装过程一切顺利就可以跳过下面的内容了 当我在终端输入 wsl --install 返回了一列数据,但显然不是安装成功 于是我输入 wsl install 时报错显示 适用于 Linux 的 Windows 子系统没有已安装的分发版。 可以通过访

    2024年02月05日
    浏览(66)
  • Pycharm中安装jupyter 以及一些会遇到的问题

    1、确保电脑安装了 anaconda 和jupyter notebook  2、在命令行 启动jupyter Notebook (启动后不要关闭这个命令窗口) 命令:juputer Notebook 成功运行后的网页界面:  3、打开Pycharm 创建新的项目 (注意是Conda) 4、 创建一个jupyter notebook的文件 5、 更改配置: 找到刚才 jupyter notebook 命令窗

    2024年02月06日
    浏览(34)
  • 在 VScode 终端上创建 nuxtjs 项目遇到的问题以及使用 GitHub 遇到的问题和一些个人笔记

    这篇文章是关于在vscode终端中创建 nuxtjs项目 的一些步骤,同时还包括了使用 Git、GitHub 的一些操作,以此文章作为笔记,仅供参考。(前提:已经安装nodejs、git) 关于nuxtjs、ssr、服务端渲染、nuxtjs项目结构等等相关知识点这篇文章就不多多介绍了,在后续的文章或笔记中也

    2024年02月09日
    浏览(57)
  • 微信小程序wxml2canvas的使用以及遇到的一些问题

    最近入坑了的一个laji(拼音)项目,各种天花乱坠、异想天开的功能,给我整头大了(菜是原罪)。具体功能呢就是需要将页面元素转为图片,然后将图片和音乐制成视频(搞不了根本搞不了,丢给后端兄弟了),当然了,不能一口吃成一个大胖子,更何况嘴都还没张开,然

    2024年02月14日
    浏览(26)
  • iOS_灵动岛<Dynamic Island>

    苹果在 iPhone 14 Pro 及 iPhone 14 Pro MAX 上推出了灵动岛。灵动岛可以通过点按、长按、轻扫来进行交互,最多支持两个应用同时“登岛”。 灵动岛全称 Dynamic Island,作为 iOS 中实时活动(Live Activities)功能的一部分,用来展示需要实时更新的消息。 展现形式 展现形式有三种:

    2024年02月12日
    浏览(27)
  • Unity适配Android12所遇到的坑记录

    unity项目将targetSdk升级至32 遇到启动黑屏、热更新失效的问题 1、项目中舍弃了unity自带的splash(毕竟功能有限) 在Java层新加了SplashView Activity 升级到12后当需要切换到unity activity的时候,无法触发unity的OnApplicationPause以及OnApplicationFocus函数。 然后就无法执行后边的逻辑直接黑屏…

    2024年02月13日
    浏览(24)
  • iOS_适配 iOS16 转屏

    问题1:iOS 16 屏幕旋转报错: [Orientation] BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported. Please use UIWindowScene.requestGeometryUpdate(_:) 解决:iOS16 UIDevice 不再支持 setValue 方法,使用 UIWindowScene 的 requestGeometryUpdate() 的方法代替 问题2: Xcode13 和 Xcode14 编译出的安装包效果不一致

    2024年02月16日
    浏览(71)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包