前端转flutter需要了解的适配方案

2,345 阅读3分钟

背景

flutter中没有长度单位,那怎么来适配不同屏幕呢?本文主要是提供给前端转flutter开发的同学一个学习的视野,了解下原生的适配方式。

移动端适配

名词解释:

物理像素: 手机的实际分辨率;  
逻辑像素(也叫设备独立像素dip): 为了适配高清屏幕抽象封装的一个概念,通过设备像素比换算;  
设备像素比(dpr): 物理像素/逻辑像素;  
像素密度(ppi): 每英寸包括的像素数;ppi越高,屏幕越清晰;  

ios/android/h5/flutter的长度单位和计算公式:

安卓(dp): 1 dp= (ppi/160)px
ios(pt): 1 pt = (ppi/163)px
h5(px): 1px(css像素) = 物理像素 / scale  
flutter(无单位,可以理解为dp): 1dp = (ppi/160)px

可以看出来,android/ios/flutter的适配方式都是通过ppi来适配的。我们先看一些例子的计算,看下ppi的适配是怎么实现的(一个宽高200px的元素,750px宽度视觉稿下的例子):

//iphone x/xs 
200pt = (462/163) * 200 = 566px // 物理像素乘以像素比@3600px,相差34px;
//iphone6
200pt = (326/163) * 200 = 400px // 物理仙像素乘以像素比@2400px,无差;
// HUAWEI P10
200db = (432/160) * 200 = 540px // 物理像素乘以像素比@3, 600px, 相差60px;  
// Oppo A37
200db = (293/160) * 200 = 366.25px // 物理像素乘以像素比@2, 400, 相差34px;

对于ios, 虽然看在iphonex上是相差34px,但其实按照实际比例来说,误差只有34/750 ~= 0.04,其实在这点差别很难看出来的; 对于安卓 60px/1080px = 0.08,差距也不会很大;
综合目前的分析,用ppi进行适配,大部分差距不大,但会在不同的版本上仍会有一点点不是很适配(但其实前端同学都知道,在实际开发中大部分元素排列是对齐方式布局的,所以不会太容易看出来差距);
h5的话目前主要方案是通过最佳视口和视觉稿的比例进行缩放,详细可以参考我另外一篇h5适配的文章。其实如果只需要开发app不考虑h5的话,可以直接使用flutter默认的单位即可,但如果考虑h5的话,就需要使用h5的方案了,因为浏览器没办法查询到ppi(也可以将所有手机型号对应的ppi都写下来的hack方式,但长期来说不利于更新)。

响应式布局

一、通过flex(row, column)设置flex的值, e.g.

body: Row(
  children: [
    Expanded(
      flex: 3,
      child: Container(color: Color(0xFFFF6666), child: Center(child: Text("30%", style: Theme.of(context).textTheme.headline2,),),),
    ),
    Expanded(
      flex: 7,
      child: Container(color: Color(0xFFFFFF66), child: Center(child: Text("70%", style: Theme.of(context).textTheme.headline2,),)),
    )
  ],
),

二、通过媒体查询计算(查询父元素size);

width: MediaQuery.of(context).size.width * 0.3

三、自己通过媒体查询实现一个基类,每次长度计算都通过这个方式来计算;(目前比较常见的三方库是flutter_screenUtil)

问题记录

1 css(px)和物理像素有什么区别?
css(px)其实是逻辑像素,跟物理像素的换算公式为 物理像素 = css像素 * @缩放因子

2 为什么h5不使用ios(pt)/android(dp)作为计算单位;
暂时没找到有相关文档,估计有可能一下原因:

1 浏览器暂时没有可以查询到ppi的api;  
2 通过视觉稿/理想视口对比, 可以得到更准确的值;  

参考文档

1 Flutter屏幕适配: juejin.cn/post/684490…
2 flutter.dev/docs/develo…
3 flutter_screenUtil: github.com/OpenFlutter…