整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

(十三) Flutter入门学习 之 屏幕适配

(十三) Flutter入门学习 之 屏幕适配

前移动端的设备已经非常多,并且不同的设备手机屏幕也不相同。

目前做移动端开发都要针对不同的设备进行一定的适配,无论是移动原生开发、小程序、H5页面。

Flutter中如何针对不同的手机屏幕来进行适配呢?我们一起来聊聊这个话题。

一. Flutter单位

1.1. Flutter中的单位

在进行Flutter开发时,我们通常不需要传入尺寸的单位,那么Flutter使用的是什么单位呢?

  • Flutter使用的是类似于iOS中的点pt,也就是point。
  • 所以我们经常说iPhone6的尺寸是375x667,但是它的分辨率其实是750x1334。
  • 因为iPhone6的dpr(devicePixelRatio)是2.0,iPhone6plus的dpr是3.0

iPhone设备参数

在Flutter开发中,我们使用的是对应的逻辑分辨率

1.2. Flutter设备信息

获取屏幕上的一些信息,可以通过MediaQuery:

// 1.媒体查询信息
final mediaQueryData=MediaQuery.of(context);

// 2.获取宽度和高度
final screenWidth=mediaQueryData.size.width;
final screenHeight=mediaQueryData.size.height;
final physicalWidth=window.physicalSize.width;
final physicalHeight=window.physicalSize.height;
final dpr=window.devicePixelRatio;
print("屏幕width:$screenWidth height:$screenHeight");
print("分辨率: $physicalWidth - $physicalHeight");
print("dpr: $dpr");

// 3.状态栏的高度
// 有刘海的屏幕:44 没有刘海的屏幕为20
final statusBarHeight=mediaQueryData.padding.top;
// 有刘海的屏幕:34 没有刘海的屏幕0
final bottomHeight=mediaQueryData.padding.bottom;
print("状态栏height: $statusBarHeight 底部高度:$bottomHeight");

获取一些设备相关的信息,可以使用官方提供的一个库:

dependencies:
  device_info: ^0.4.2+1


二. 适配方案

2.1. 适配概述

假如我们有下面这样一段代码:

  • 在屏幕中间显示一个200*200的Container
  • Container中有一段文字是30
class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("首页"),
      ),
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          color: Colors.red,
          alignment: Alignment.center,
          child: Text("Hello World", style: TextStyle(fontSize: 30, color: Colors.white),),
        ),
      ),
    );
  }
}

上面的代码在不同屏幕上会有不同的表现:

  • 很明显,如果按照上面的规则,在iPhone5上面,尺寸过大,在iPhone6plus上面尺寸过小
  • 在开发中,我们应该可以根据不同的屏幕来完成尺寸的缩放

不同屏幕表现


在前端开发中,针对不同的屏幕常见的适配方案有下面几种:

  • rem:
    • rem是给根标签(HTML标签)设置一个字体大小;
    • 但是不同的屏幕要动画设置不同的字体大小(可以通过媒体查询,也可以通过js动态计算);
    • 其它所有的单位都使用rem单位(相对于根标签);
  • vw、wh:
    • vw和vh是将屏幕(视口)分成100等份,一个1vw相当于是1%的大小;
    • 其它所有的单位都使用vw或wh单位;
  • rpx:
    • rpx是小程序中的适配方案,它将750px作为设计稿,1rpx=屏幕宽度/750;
    • 其它所有的单位都使用rpx单位;

这里我采用小程序的rpx来完成Flutter的适配

2.2. rpx适配

小程序中rpx的原理是什么呢?

  • 不管是什么屏幕,统一分成750份
  • 在iPhone5上:1rpx=320/750=0.4266 ≈ 0.42px
  • 在iPhone6上:1rpx=375/750=0.5px
  • 在iPhone6plus上:1rpx=414/750=0.552px

rpx的对应关系


那么我们就可以通过上面的计算方式,算出一个rpx,再将自己的size和rpx单位相乘即可:

  • 比如100px的宽度:100 * 2 * rpx
  • 在iPhone5上计算出的结果是84px
  • 在iPhone6上计算出的结果是100px
  • 在iPhone6plus上计算出的结果是110.4px

我们自己来封装一个工具类:

  • 工具类需要进行初始化,传入context
    • 可以通过传入context,利用媒体查询获取屏幕的宽度和高度
    • 也可以传入一个可选的参数,以什么尺寸作为设计稿
class HYSizeFit {
  static MediaQueryData _mediaQueryData;
  static double screenWidth;
  static double screenHeight;
  static double rpx;
  static double px;

  static void initialize(BuildContext context, {double standardWidth=750}) {
    _mediaQueryData=MediaQuery.of(context);
    screenWidth=_mediaQueryData.size.width;
    screenHeight=_mediaQueryData.size.height;
    rpx=screenWidth / standardWidth;
    px=screenWidth / standardWidth * 2;
  }
  
  // 按照像素来设置
  static double setPx(double size) {
    return HYSizeFit.rpx * size * 2;
  }
  
  // 按照rxp来设置
  static double setRpx(double size) {
    return HYSizeFit.rpx * size;
  }
}

初始化HYSizeFit类的属性:

  • 注意:必须在已经有MaterialApp的Widget中使用context,否则是无效的
class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 初始化HYSizeFit
    HYSizeFit.initialize(context);
    return null;
  }
}

使用rpx来完成屏幕适配:

class HYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    HYSizeFit.initialize(context);
    return Scaffold(
      appBar: AppBar(
        title: Text("首页"),
      ),
      body: Center(
        child: Container(
          width: HYSizeFit.setPx(200),
          height: HYSizeFit.setRpx(400),
          color: Colors.red,
          alignment: Alignment.center,
          child: Text("Hello World", style: TextStyle(fontSize: HYSizeFit.setPx(30), color: Colors.white),),
        ),
      ),
    );
  }
}

我们来看一下实现效果:

rpx适配方案


屏幕适配也可以使用第三方库:flutter_screenutil

  • https://github.com/OpenFlutter/flutter_screenutil

原文出处:https://mp.weixin.qq.com/s/z21YZ4FhSswpDWn4KpK6jw(侵权删除)

着网络与科技的快熟发展,越来越多的手机厂商开始打起手机之间的战争,手机的快速发展也使得越来越多的人开始使用手机上网。移动设备正超过桌面设备,成为访问互联网的最常见终端。那么就会出现一个问题,如何才能让PC端的网页在手机上正常显示?手机与PC的屏幕宽度有着很大的区别,会造成同样的内容在手机与PC端出现两种不同的显示结果。那该如何才能使得手机与PC都能对网页呈现出令人满意的结果呢,本文收集了以下几种方法,有兴趣的小伙伴们可以看下:

1、在网页代码的头部,加入一行viewport元标签。

viewport是网页默认的宽度和高度,上面这行代码的意思是,网页宽度默认等于屏幕宽度(width=device-width),原始缩放比例(initial-scale=1)为1.0,即网页初始大小占屏幕面积的100%。

注意:该方式不支持IE8及IE8以下的版本

2、不使用绝对宽度

由于网页会根据屏幕宽度调整布局,所以不能使用绝对宽度的布局,也不能使用具有绝对宽度的元素。对图像来说也是这样。

具体说,CSS代码不能指定像素宽度:width:xxx px;

只能指定百分比宽度: width: xx%; 或者 width:auto;

3、使用相对大小的字体

字体也不能使用绝对大小(px),只能使用相对大小(em或者rem)

例如: body

上面的代码指定,字体大小是页面默认大小的100%,即16像素(1em=16px)。

h1

h1的大小是默认大小的1.5倍,即24像素(24/16=1.5)

将想要的像素去除默认的16像素可以得到em

4、流动布局(fluid grid)

"流动布局"的含义是,各个区块的位置都是浮动的,不是固定不变的。

.main

.leftBar

float的好处是,如果宽度太小,放不下两个元素,后面的元素会自动滚动到前面元素的下方,不会在水平方向overflow(溢出),避免了水平滚动条的出现。

5、媒体查询器@media

"自适应网页设计"的核心,就是CSS3引入的MediaQuery模块。

它的意思就是,自动探测屏幕宽度,然后加载相应的CSS文件。

上面的代码意思是,如果屏幕宽度小于400像素(max-device-width: 400px),就加载tinyScreen.css文件。

如果屏幕宽度在400像素到600像素之间,则加载smallScreen.css文件。

辑导语:虽然国内软件的iPad用户占比不大,但依然存在着横屏适配的需求。本文作者讲述了自己做iPad横屏适配的背景,并对竞品的适配方式进行了分析研究,用自己的亲身经历提供了参考,推荐对ipad横屏适配感兴趣的童鞋阅读。

一、背景

在我参与的一款资料查询 App 中,对 iPad 只支持竖屏以手机 UI 尺寸拉伸,每个季度都有用户反馈希望适配 iPad 横屏。经过询问用户发现,因为 iPad mini 尺寸刚好可以放在工作服口袋中,随时拿出来使用,而 iPad 屏幕远比手机大,浏览资料视野更大更舒服。

但另外一方面,后台数据显示当前 iPad 用户占比只有 1%,用户呼声够不上星星之火,不足以燎原。先别谈说服团队做 iPad 横屏适配,连说服自己都难。本来以为这事就像水中投石,水波消散就没有下文了。直到有一天,同样是资深用户的高管自己拿着 iPad 装上我们的 App 用了几天,终于忍不了,开始推动 iPad 横屏适配。

二、参考

我们肯定不是第一个做 iPad 横屏适配的,但在网上搜了一圈,别说横屏适配,连 iPad 界面设计的文章都很少,下面 3 篇算不错的。这也是我决定写下本文的原因,为后来者提供经验,少踩坑。

  1. 《利用好 iPad 的大屏幕 —— 如何为 iPadOS 14 设计 app?》,https://steppark.net/15942969497015.html
  2. 《iPad 交互设计探索系列:iPad 适用产品篇》,https://www.jianshu.com/p/65211fddefb9
  3. 《iPad 交互设计探索系列:iPad 导航设计篇》,https://www.jianshu.com/p/0c8e315d39d4

三、研究

没得经验参考就只能先从竞品分析开始了。经过对 iOS 系统应用、微信、QQ、微信阅读、得到、豆瓣、淘宝和有道词典的分析,我和同事总结成 5 种横屏适配模式。

1. 内容响应式

典型 App:iOS 应用商店

特征:标题栏和 Tabbar 通栏拉伸,内容区根据宽度向右响应式布局。

适用场景:全部场景。

评价:灵活性和用户体验都很好,但设计和开发成本很大。

2. 左右分栏

典型 App:iOS 设置、淘宝、微信、QQ

特征:左右分开显示,左边通常固定显示首页或者目录导航。右侧根据左侧选择显示对应的详情内容。

适用场景:频繁需要使用导航切换内容。

评价:用户体验适中,合理的利用横屏更大地展示更多的内容。设计成本小,需额外设计一个右侧默认为空的情况。开发成本要看是否改程序架构,相当于把手机两个手机界面合并成一个屏幕,可能有些程序架构很难这么修改。

3. 按竖屏宽度显示

典型 App:微信阅读

特征:标题栏和 Tabbar 通栏拉伸,内容直接按竖屏的宽度显示。

适用场景:全部场景。

评价:用户体验适中,设计与开发成本小,大多数产品采用此模式,但是没有更好的展现横屏宽屏的优势。

4. 全屏通栏拉伸

典型 App:豆瓣

特征:横屏为全屏通栏拉伸,所有元素与竖屏一致。

适用场景:全部场景。

评价:设计和开发成本最小,但是相当于没有适配。用户体验较差,横屏情况下内容集中,左侧右侧很空,或者被拉得很长,阅读体验较差。

5. 混合模式

当然也不是所有 App 都采用单一的模式。比如微信阅读,在其他页面是按竖屏宽度显示。但到了图书阅读界面,则是左右分栏充分利用 iPad 大屏幕展现内容。

以上竞品分析所有截图我们都保存在 Figma 中,有需要的读者可前往获取。

链接:https://www.figma.com/community/file/1071850659054902697/iPad-横屏适配竞品分析

四、执行

非常遗憾的是虽然高管牵头做适配,但开发资源确实有限。不能为了设计师邀功拿业绩就从头把 iOS App 重构一遍,因此我们决定用最少的资源做最核心的优化。

适配计划分为 2 期。第 1 期将所有页面用按竖屏宽度显示进行横屏适配。第 2 期挑选核心页面用内容响应式或左右分栏进行优化。

1. 先开发再验收

在第 1 期我们就踩坑了,按照原来的工作流程,我们将所有的 iPad 横屏页面做好线框图、再输出所有视觉效果图。虽然都是线上页面不用重新设计,只需要拉伸画面或者调整间距,但所有线上页面也是一个不小的工作量。

就在进行过程中,iOS 工程师就皱着眉头来提议,由于代码架构和资源所限,设计师如果调整的视觉效果图未必能 100% 实现。不如反过来,让他先把所有页面强行横屏,再由设计师走查发现问题进行修改,这样节省时间效果也可控。

可见,不同的项目类型可以采取不同的工作流程。iPad 横屏适配项目流程和常规工作流程刚好相反,以往是先设计再开发,改成先开发再走查,节省设计师产出效果图时间,也保障最终实现效果。

2. 核心场景决定核心页面

在第 2 期挑选核心页面时,我也犯了错误。最开始我觉得核心是脸面,因此挑选 Tabbar 导航的首页、个人中心等用户一打开 App 就看得到的页面进行优化。但实际上用户真正的核心使用场景是在详情页查阅资料,这才是真正的核心页面。

在得到主管纠正后,我们转而开始为资料阅读页面提供左内容右目录的布局,便于用户方便地在长文中精确定位想读的内容。

2 期计划并非适配的终结,随着 App 功能的迭代,此后老界面修改和新界面设计需要考虑到 iPad 横屏的适配问题,就成为了日常工作的内容了。

五、总结

按照以往的项目总结,最后应该汇报项目数据结果。但由于 iPad 用户本身可怜的占比,即使我们官方公众号推文宣布适配 iPad 横屏后,也没有 iPad 用户站出来点赞,而是又引发出使用华为、小米等安卓 Pad 的用户,要求也适配。

考虑到不同的安卓品牌适配方式不一样,而且安卓厂商自己又有平行世界等通用兼容方案,我们就没再继续参与了。

虽然没有外部用户反馈,但公司内部同事和开发团队使用后确实感觉很棒。所以我觉得这次适配项目真正值得思考的是:如果一个需求用户反馈很少,也没有数据支撑,但对体验影响很大,如何推动团队进行优化呢?

作者:龙爪槐守望者,微信公众号:龙爪槐守望者

本文由 @龙爪槐守望者 原创发布于人人都是产品经理。未经许可,禁止转载。

题图来自 Unsplash,基于 CC0 协议