Flutter学习-屏幕适配

Posted GY-93

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter学习-屏幕适配相关的知识,希望对你有一定的参考价值。

目前移动端设备非常多,并且不同的设备手机屏幕也不相同。
目前做移动端开发都要针对不同的设备进行一定的匹配,无论是移动原生开发、小程序、H5页面
那么下面我们来学习下,Flutter中如何针对不同的手机屏幕来进行适配

1. Flutter的单位

1.1 Flutter中的单位

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

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

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

1.2 Flutter的设备信息

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

//获取媒体查询信息对象
          final mediaQueryData = MediaQuery.of(context);
          //获取屏幕的宽度和高度
          final kScreenWidth = mediaQueryData.size.width;
          final kScreenHeight = mediaQueryData.size.height;
          final phySicalWidth = window.physicalSize.width;
          final phySicalHeight = window.physicalSize.height;

          final dpr = window.devicePixelRatio;

          print("屏幕的宽度===$kScreenWidth, 屏幕的高度===$kScreenHeight");
          print("分辨率: phySicalWidth==$phySicalWidth, phySicalHeight===$phySicalHeight");
          print("dpr=======$dpr");

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

1.3 在程序开始时获取设备信息

假如我们希望程序运行起来的开始就拿到这些屏幕的信息,我们在MyApp的build方法中写这样一段代码:

这个时候程序运行起来会报错:

是说MediaQuery这个对象不存在,为什么会不存在了 我们可以去查看源码:

当我们在MyApp中的build方法获取MediaQuery对象时, runApp方法还没有走完,MediaQuery还没有创建

其实我们仔细的产看MediaQueryfromWindow初始化方法,我们可以发现size对象是通过Window对象的某些属性计算来赋值,那我们完全可以绕过MediaQuery对象直接使用window对象来获取我们需要的屏幕信息

可以window直接获取,绕过MediaQuery对象

如果还需要获取一些其它信息,我们可以参考上述源码,直接通过window来获取信息

1.4 官网提供三方库获取设备相关信息

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

dependencies:
  device_info: ^2.0.2

2. 适配方案

2.1 常用的适配方案

加入我们有下面这样一段代码

  • 在屏幕中间显示一个200*200的Container
  • Container中有一端文字是30
class GYHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return 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适配

最终我们把这个写代码封装成一个工具类(extension(扩展) + 单利 )来实现的


import 'dart:ui';

class GYSizeFit  {
  double phySicalWidth = 0;
  double phySicalHeight = 0;

  double screenWidth = 0;
  double screenHeight = 0;

  double dpr = 0;
  double px = 0;

  double statusBarHeight = 0;
  double bottomHeight = 0;

  //初始化
  static void initialize() {

  }
  //工厂方法构造函数
  factory GYSizeFit() => _getInstance();

  //instance的getter方法
  static GYSizeFit get instance => _getInstance();

  //静态变量 _instace, 存储唯一对象
  // 这里必须要使用? 声明可选值, 不然不可以赋值null
  static GYSizeFit? _instance = null;

  //获取对象
  static GYSizeFit _getInstance() {
    if (_instance == null) {
      //使用私有构造方法来创建对象
      _instance = GYSizeFit._internal();
    }

    return _instance!;
  }

   //私有的命名构造法方法 ,默认的构造方法将失效, 这样就隐藏了构造方法
  //子类不能继承internal
  //不是关键字,可定义其它名字
  GYSizeFit._internal() {
    // 初始化
    //分辨率
    phySicalWidth = window.physicalSize.width;
    phySicalHeight = window.physicalSize.height;

    // 屏幕宽高
    screenWidth = window.physicalSize.width / window.devicePixelRatio;
    screenHeight = window.physicalSize.height / window.devicePixelRatio;

    //这里是以iphone6 为模板来适配的
    dpr = screenWidth/750 ; // 像素点适配
    px = screenWidth/750 * 2; // 物理宽度适配

    //导航栏和底部工具栏的高度
    statusBarHeight = window.padding.top;
    bottomHeight = window.padding.bottom;
  }
}

//给double写一个分类
extension sizeFit on double {
  //使用像素适配大小
  double dpx() {
    return this * GYSizeFit.instance.dpr;
  }

  // 使用px(物理宽度适配)
  double px() {
    return this * GYSizeFit.instance.px;
  }
}

使用的方法:

所有设计到尺寸的都可以调用这个方法来适配

以上是关于Flutter学习-屏幕适配的主要内容,如果未能解决你的问题,请参考以下文章

Flutter屏幕像素适配方案 ( flutter_screenutil 插件 )

Flutter MediaQuery获取屏幕信息以及屏幕适配

flutter 屏幕尺寸适配字体大小适配

flutter屏幕适配

11-Flutter移动电商实战-首页_屏幕适配方案和制作

Flutter中屏幕适配,尺寸设置