Flutter-适配相关

Flutter-适配相关,第1张

Flutter-适配相关 一、前言

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

Container(
  width: 40,
  height: 40,
),

那么这个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'),
    ),
  ));
}

通过Flutter的DevTool查看:

可以看到这里的尺寸显示的是 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)),
        ))
      ),
    ),
  ));
}

运行效果图:

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

通过这个图,我们能明确的看到每个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设备上会出现什么情况呢?

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

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

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

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

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

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

根据上面的原理描述,下面我们实现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;

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

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

第一步:

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

第二步:

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

Container(
    width: SizeFit.dpToSize(60),
    height: SizeFit.dpToSize(60),
    )

总参考如下:

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)),
                  ))),
    );
  }
}

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

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

}

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

Container(
    width: 60.dp,
    height: 60.dp,
    )
最后:
  1. 通过上面的描述,我们了解的flutter的尺寸的含义
  2. 如果不做适配,在不同的机型上,可能达不到预期的设计效果
  3. 了解适配的实现原理,提供适配方案
  4. 在pub.dev上面有其他的适配库,但是我们应该要了解适配问题以及适配方案的原理,这样后期可以根据需求随时定制。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5686925.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存