Flutter Web - 如何适配 iphone 安全区域
Flutter Web 系列
(提前预警,本文多图)
昨日正在将 Flutter Web 的实现的页面放入微信小程序中看下效果,突然发现在 iphoneX 设备上,底部安全区域没有适配成功,如下图:
排查过程
作为一个标准流程的程序员,出问题了都是要先自我怀疑一遍。
检查 Flutter 代码
显式声明了 SafeArea
,再没什么特别的了
检查微信小程序代码
公司的小程序代码比较骚一点,用 taro
实现的。
想当然的搜了下前端处理 iphone 安全区域的文章,都是推荐增加样式即可。
@supports (bottom: constant(safe-area-inset-bottom)) or
(bottom: env(safe-area-inset-bottom)) {
webview {
margin-bottom: constant(safe-area-inset-bottom);
margin-bottom: env(safe-area-inset-bottom);
}
}
然而并没有什么卵用,又查了下 taro
的开发文档也没有什么特别的介绍。
最后查小程序文档时,找到这么一句
看起来是不能在小程序侧解决这个问题的。
尝试在 Web 上解决
那我们能不能在 Web 侧解决问题,毕竟 Flutter Web 终究还是 Web,在 index.html
加个 css 样式不就行了。
但并不可行,
强行对渲染的标签增加 margin-bottom: 30px;
结果令人尴尬
标签确实顶上去了,但内容没变化 [猝死]。
想了想原因,应该是 Flutter 在实现 Web 上大都是使用的绝对定位(具体是如何实现的没有去源码里找)。
解决方式
自我怀疑结束,那就官方寻找解决方案了。git 不欺我,搜索一下 safeArea 还是很容易找到 issues 的。issues 传送门
这问题竟然都 open 一年半了,还是 P3 级的,Flutter 官方竟然一直都不解决,这是多瞧不起 iOS safari [狗头*2]。
好在下面评论里有人发了解决方案,也有一个可用的 npm 包 safeAreaInsets
但本着不乱引用三方库的习惯,看了它源码,也十分简单,就一个文件,具体原理就是构造一个绝对定位的 div
然后增加 safe-area-inset-bottom
CSS,再通过 JS 去获取这个 div
的 top
, bottom
即可。
那就没必要引入 npm 包了,直接改成一个工具类拿来即用。
也没必要手写评论里的 Flutter TS 链接类。
![Flutter Web - 如何适配 iphone 安全区域](https://img.blogweb.cn/article/eda4ad3394f64fa9a5e04e2e4ea73e6b.webp)
我们有 TS2dart
工具,想要工具的同学可以看下这篇 《# Vite + Flutter:打造不一样的前端框架(附源码)》
api.ts
export class GDGlobal {
/**
* 安全区域
*/
static safeAreaInsets: GDSafeAreaInsets
}
...
/**
* 安全区域
*/
export interface GDSafeAreaInsets {
/**
* 上
*/
top: number
/**
* 下
*/
bottom: number
/**
* 左
*/
left: number
/**
* 右
*/
right: number
/**
* 是否支持
*/
support: boolean
}
TS 定义一下,这样就可以直接在 Flutter 项目里使用了。
SafeArea( // 还是保留了 SafeArea
child: Container( // 增加一个 Container 用于增加 padding
padding: EdgeInsets.only(
// 直接调用即可
bottom: GDGlobal.safeAreaInsets.bottom.toDouble(),
),
child: BottomNavigationBar(
),
...
),
好了,我们再试一下,还是没生效,WTF??
想想 safe-area-inset-bottom
生效的必要条件,想到是因为项目里没加 viewport-fit=cover
,如果是 Vue 开发的移动端项目一开始就会加,但 Flutter Web 上总是有些疏漏。
index.html
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
...
可以了,底部栏总算是在安全区域内了。
但 BottomNavigationBar
这官方组件竟然自带底部阴影,也是我没想到的 ...
![Flutter Web - 如何适配 iphone 安全区域](https://img.blogweb.cn/article/61ab3082aaa04e3681182f847156c07e.webp)
解决也很简单,增加 elevation: 0
即可。
总结
为什么 Flutter 官方1年半也不解决这个 P3 级问题?笔者想了下原因,大概是 Flutter 不希望使用 Web 的解决方式。一旦是桌面模式的 Web 页面,也不能乱加 viewport-fit=cover
。
而且受众面确实很小,本来 Flutter web 的项目就不多,而且在手机浏览器上都是有底部操作栏的,除非是笔者这样用 web-view 嵌套在小程序或者“添加到主屏幕”这样的方式 ...
转载自:https://juejin.cn/post/7177192190794268728