当前位置:   article > 正文

Flutter-适配相关_flutter 适配

flutter 适配

一、前言

做移动应用开发,各个系统都自己的适配方案,比如Android可以用dp、sp来描述大小,IOS使用pt来描述。但是入手Flutter后,却发现我们要描述的widget的大小没有单位,比如

Container(
  width: 40,
  height: 40,
),
  • 1
  • 2
  • 3
  • 4

那么这个40到底是什么意思呢?px、dp或者dp,其实都不是。

二、了解的Flutter的尺寸

测试手机信息:720 * 1080 320dpi。

运行以下测试代码

void main(){
  runApp(MaterialApp(
    theme: ThemeData(
      primarySwatch: Colors.blue,
    ),
    home: Scaffold(
      appBar: AppBar(
        title: const Text('适配测试'),
      ),
      body: const Text('Hello world'),
    ),
  ));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

通过Flutter的DevTool查看:
image

可以看到这里的尺寸显示的是 w = 360.0,h = 540.0

下面修改我们的代码,水平添加6个 width为60的Contaniner:

void main(){
  runApp(MaterialApp(
    theme: ThemeData(
      primarySwatch: Colors.blue,
    ),
    home: Scaffold(
      appBar: AppBar(
        title: const Text('适配测试'),
      ),
      body:  Row(
        children: List.generate(6, (index) => Container(
          width: 60,
          height: 60,
          color: Color.fromARGB(255,Random().nextInt(255), Random().nextInt(255), Random().nextInt(255)),
        ))
      ),
    ),
  ));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行效果图:

image

刚好占据整个屏幕,下面哦我们通过DevTools看一下内部的布局情况:

image

通过这个图,我们能明确的看到每个Container的w = 60,h = 60;6个Container刚好占据360的宽度。

所以Flutter中的大小是逻辑像素,与设备的分辨率和密度相关。
比如720 * 1080 dpi为320的设备,与大小为360 * 540;在比如Iphone6,750 * 1334,大小为375 * 667;因此我们设置的大小实际上为独立的值。

了解Flutter的尺寸的意义后,在开中我们应该注意什么呢? 那就是适配问题;比如上面的代码在720 * 1080 dpi为320的设备上运行没有问题,那么换到 480 * 800 dpi为240设备上会出现什么情况呢?

image

提示已经超过了最大宽度。接下里通过DevTools都看一下内部的布局呢:
image

可以看出这里宽度变为了320,而我们每个Container的宽度是60,6个的总宽度360 > 320。

从上面的描述,我们可以看出Flutter的尺寸单位:是逻辑像素,和设备的 devicePixelRatio和分辨率相关

显然,若果我们不对某些widget的大小做适配,就可能达不到我们预期设计的效果,因此接下里我们要处理的就是适配问题了。

三、Flutter在移动端的适配方案

适配和我们的设计稿相关,比如375 * 667的设计稿,上面一个图片大小为100 * 100,那么320 * 453的设备上,大小该是多少呢?这里做一个比例缩放就行了,320/375 ≈ 0.85 ,因此在320 * 453的设备上图片大小是85 * 85。这样就能够适配我们的屏幕了。如下图:
image

根据上面的原理描述,下面我们实现Flutter在移动端的适配:

新建一个size_fit.dart

class WTSizeFit {
  //物理尺寸宽度
  static late double physicalWidth;

  //物理尺寸高度
  static late double physicalHeight;

  //像素密度
  static late double devicePixelRatio;

  ///
  ///屏幕像素相对宽度-
  ///比如:物理像素750*1334的iphone6 screenWidth则为375
  ///720 * 1080的android设备,screenWidth为 360
  ///
  static late double screenWidth;

  ///
  /// screenHeight和screenWidth对应
  ///
  static late double screenHeight;

  static late double statusBarHeight;

  //
  static late double bottomBarHeight;

  ///
  /// 宽度缩放比
  ///
  static late double widthScaleRatio;

  ///
  /// 设计稿宽度-使用像素
  ///
  static late double _designWidth;

  static void initialize({double designWidth = 375}) {
    _designWidth = designWidth;
    physicalWidth = window.physicalSize.width;
    physicalHeight = window.physicalSize.height;
    devicePixelRatio = window.devicePixelRatio;
    screenWidth = physicalWidth / devicePixelRatio;
    screenHeight = physicalHeight / devicePixelRatio;
    statusBarHeight = window.padding.top / devicePixelRatio;
    bottomBarHeight = window.padding.bottom / devicePixelRatio;

    widthScaleRatio = screenWidth  / _designWidth;
  }

  ///
  /// pt或者dp都可以使用该方法
  ///
  static double dpToSize(num dp) => dp * widthScaleRatio;

  ///
  /// sp也使用dp的方式进行视适配
  ///
  static double spToSize(num sp) => sp * widthScaleRatio;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

这里根据平时移动端的开发经验,做宽度的适配就可以,高度可以不用考虑,其他场景可以根据该原理进行修改。

在开发中我们可以这样使用:

第一步:

MyApp的build方法中进行初始化:SizeFit.initialize();

第二步:

设置大小的地方按以下方式进行使用:

Container(
    width: SizeFit.dpToSize(60),
    height: SizeFit.dpToSize(60),
    )
  • 1
  • 2
  • 3
  • 4

总参考如下:

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    SizeFit.initialize();
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MainPage(),
    );
  }
}
class MainPage extends StatelessWidget {
  const MainPage({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
          children: List.generate(
              6,
              (index) => Container(
                    width: SizeFit.dpToSize(60),
                    height: SizeFit.dpToSize(60),
                    color: Color.fromARGB(255, Random().nextInt(255),
                        Random().nextInt(255), Random().nextInt(255)),
                  ))),
    );
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

这样做以后满足了我们的屏幕的适配,但是每次都调用SizeFit.dpToSize()有点麻烦,这里我们可以使用扩展方法

extension SizeExtension on num{
  double get dp => WTSizeFit.dpToSize(this);
  double get sp => WTSizeFit.spToSize(this);

}
  • 1
  • 2
  • 3
  • 4
  • 5

接下来按以下方式进行调用:

Container(
    width: 60.dp,
    height: 60.dp,
    )
  • 1
  • 2
  • 3
  • 4

最后:

  1. 通过上面的描述,我们了解的flutter的尺寸的含义
  2. 如果不做适配,在不同的机型上,可能达不到预期的设计效果
  3. 了解适配的实现原理,提供适配方案
  4. 在pub.dev上面有其他的适配库,但是我们应该要了解适配问题以及适配方案的原理,这样后期可以根据需求随时定制。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/227363?site
推荐阅读
相关标签
  

闽ICP备14008679号