bonus推荐项目,最高 40% 奖励!推荐项目 →
无矩
解决方案文档库了解我们博客联系方式
菜单
编写 Safe Area 组件约束用户界面
← 回到文章列表
大前端

如今在移动设备领域,消费者随身携带的显示器呈现出了多样化的设计,不再限制于简单的矩形块。面对尺寸不一、形状各异的设备,开发者们如何确保提供给用户的内容和交互不受影响呢?

由 iPhone X 说起

Apple 推出了以 iPhone X 为代表的异形屏方案后,提供了相应的视觉设计指南。其中提到了 Safe Area 的定义,我们用一张图片来演示 Safe Area 在 iPhone 上的应用:

基于 iPhone 的 Safe Area 演示

其实 Safe Area 不是一个新鲜的概念,它最早源自于电视生产领域,用于描述在电视屏幕上看到的区域。

简单地说,安全区域 ≈ 主要视觉区域 + 实际交互区域。如 iPhone X 的 Home 指示条的设计,虽然在视觉上是隐藏的,但由于它会响应系统的滑动手势,不能把控制功能放在此处。

结论

这给我们的启示是:除了极少数的场景,我们应该把渲染出来的内容放在一个名为 SafeArea 的组件内

类似在 Flutter 中,

Widget build(BuildContext context) {
  return SafeArea(child: Container());
}

就确保内容 Container() 放置在了 Safe Area 内。

构建 <SafeArea />

构建 <SafeArea /> 组件的原理其实很简单:通过操作系统提供的接口获取显示边距。

Widget build(BuildContext context) {
  assert(debugCheckHasMediaQuery(context));
  final MediaQueryData data = MediaQuery.of(context);
  EdgeInsets padding = data.padding;
  // Bottom padding has been consumed - i.e. by the keyboard
  if (data.padding.bottom == 0.0 && data.viewInsets.bottom != 0.0 && maintainBottomViewPadding)
    padding = padding.copyWith(bottom: data.viewPadding.bottom);

  return Padding(
    padding: EdgeInsets.only(
      left: math.max(left ? padding.left : 0.0, minimum.left),
      top: math.max(top ? padding.top : 0.0, minimum.top),
      right: math.max(right ? padding.right : 0.0, minimum.right),
      bottom: math.max(bottom ? padding.bottom : 0.0, minimum.bottom),
    ),
    child: MediaQuery.removePadding(
      context: context,
      removeLeft: left,
      removeTop: top,
      removeRight: right,
      removeBottom: bottom,
      child: child,
    ),
  );
}

一个例子:小程序

当然,我们并不总是在操作系统层面上去实现应用。典型的如小程序运行环境,我们无法直接拿到 ViewInsets 的数据。

其实在 iPhone X 推出前夕,WebKit 就发布了网站的适配指南

简单的两步:

一、设置视口的布局方式(小程序不需要设置)

<meta name="viewport" content="... viewport-fit=cover">

二、设置主体元素的内边距

.SafeArea {
  padding-top: env(safe-area-inset-top);
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
}

其中 safe-area-inset-* 属性是由系统代理的环境变量,也可以通过加入自定义的 var,

.SafeArea {
  padding-top: max(--minimum-top, env(safe-area-inset-top));
  padding-right: max(--minimum-right, env(safe-area-inset-right));
  padding-bottom: max(--minimum-bottom, env(safe-area-inset-bottom));
  padding-left: max(--minimum-left, env(safe-area-inset-left));
}

瞧,是不是跟 Flutter 官方的 SafeArea 组件形式一致了。

lhzbxx 发布于 2022 年 01 月 08 日;如果有疑问或需要讨论,请发送私信给我。
无矩
解决方案
通用 Web 开发系统集成物联网丨智能硬件跨平台 App 开发WeChat在线咨询
© 2022 无矩(上海)技术咨询中心
备案 沪公网安备 31011202013256 号