Flutter屏幕适配的三种方案

做移动端开发的同学都知道,针对不同型号和尺寸的手机要进行页面的适配,且 iOS 和 Android 适配方案各不相同,那我们用 Flutter 开发要怎么处理屏幕适配呢?

Flutter中的单位

Flutter使用的是类似于iOS中的点pt,也就是point。我们经常说 iPhone8 的尺寸是375x667,但是它的分辨率其实是 750x1334 。因为iPhone8的像素比(devicePixelRatio)是2.0,iPhone8plus的像素比是3.0。

iPhone各型号设备的尺寸

Flutter屏幕适配的三种方案_第1张图片

Flutter 中获取设备信息

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

device_info: ^2.0.3
//获取设备的信息
Future getDeviceInfo() async{
  DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
  var dataInfo;
  //判断是iOS平台还是Android平台
  //IosDeviceInfo里面包含我们常用到的设备信息
  if(Platform.isIOS) {
    print('IOS设备:');
    IosDeviceInfo iosInfo = await deviceInfo.iosInfo;dataInfo = iosInfo;
  } else if(Platform.isAndroid) {
    print('Android设备');
    AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;dataInfo = androidInfo;
  }
  return dataInfo;
}

获取屏幕的尺寸

需要引入

import'dart:ui';

获取屏幕的宽高、刘海高度、分辨率等信息

// 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;

// 3.状态栏的高度// 有刘海的屏幕:44 没有刘海的屏幕为20final statusBarHeight = mediaQueryData.padding.top;
// 有刘海的屏幕:34 没有刘海的屏幕0final bottomHeight = mediaQueryData.padding.bottom;
print('屏幕width:$screenWidth height:$screenHeight');
print('分辨率: $physicalWidth * $physicalHeight');
print('像素比: $dpr');
print('状态栏height: $statusBarHeight 底部高度:$bottomHeight');

打印出的设备尺寸

Performing hot restart...
Syncing files to device iPhone 12 Pro...
Restarted application in 575ms.
flutter: 屏幕width:390.0 height:844.0
flutter: 分辨率: 1170.0 * 2532.0
flutter: 像素比: 3.0
flutter: 状态栏height: 47.0 底部高度:34.0

适配方案

1.通过等比换算的方式

计算公式:实际尺寸 = UI尺寸 * 设备宽度/设计图宽度

这里封装了一个类Adapt,通过类可以获取屏幕的信息

class Adapt {
  
  static double screenWidth = 0;
  static double screenHeight = 0;
  static double physicalWidth = 0;
  static double physicalHeight = 0;
  static double dpr = 0;
  static double ratio = 1.0;
  static double statusBarHeight = 0;
  static double bottomHeight = 0;

  static void initialize(BuildContext context, {double UIWidth = 375}) {
    // 1.媒体查询信息
    final mediaQueryData = MediaQuery.of(context);

    // 2.获取宽度和高度
    screenWidth = mediaQueryData.size.width;screenHeight = mediaQueryData.size.height;physicalWidth = window.physicalSize.width;physicalHeight = window.physicalSize.height;
    //像素比
    dpr = window.devicePixelRatio;

    // 3.状态栏的高度
    // 顶部有刘海:47pt 没有刘海的屏幕为20pt
    statusBarHeight = mediaQueryData.padding.top;
    // 底部有刘海:34pt 没有刘海的屏幕0pt
    bottomHeight = mediaQueryData.padding.bottom;
    //比例
    ratio = screenWidth/UIWidth;
  }

  static pt(size){
    return size * Adapt.ratio;
  }
}
示例代码

UI给出的设计稿的尺寸是375*667,定义一个大小为(300*300)pt的盒子,盒子中显示字体大小为30pt的文字

@override
Widget build(BuildContext context) {
  Adapt.initialize(context);
  returnScaffold(
    appBar: AppBar(
      title: const Text('屏幕适配'),
    ),
    body: Center(
      child: Container(
        width: Adapt.pt(300),
        height: Adapt.pt(300),
        color: Colors.orange,
        alignment: Alignment.center,
        child: Text(
          'Hello Word',
          style: TextStyle(fontSize: Adapt.pt(30)),
          textAlign: TextAlign.center,
        ),
      ),
    ),
  );
}

运行效果图,明显右边做适配的更符合效果

Flutter屏幕适配的三种方案_第2张图片

2. rpx方案适配

rpx是小程序中的适配方案,它将750px作为设计稿,1rpx=屏幕宽度/750,其它所有的单位都使用rpx单位。

  • 不管是什么屏幕,统一分成750份

  • 在iPhone8上: 1rpx = 375/750 = 0.5px

  • 在iPhone12proMax 上:1rpx = 428/750 = 0.571px

所以我们就可以通过上面的计算方式,算出一个rpx,再将自己的size和rpx单位相乘即可:比如300px的宽度:3002rpx

  • 在iPhone8上计算出的结果是300px

  • 在在iPhone12proMax上计算出的结果是342.6px通过计算可以看出,还是有明显数据上的差别的。

这里也是封装一个类 Adapt,直接可以获取屏幕的信息

class Adapt {
  static MediaQueryData _mediaQueryData = MediaQueryData();
  static double screenWidth = 0;
  static double screenHeight = 0;
  static double rpx = 0;
  static double px = 0;

  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 Adapt.rpx * size * 2;
  }

  // 按照rxp来设置
  static double setRpx(double size) {
    return Adapt.rpx * size;
  }
}
示例代码

和上面的需求是一样的,最后适配的效果是一样的

@override
Widget build(BuildContext context) {
  Adapt.initialize(context);
  returnScaffold(
    appBar: AppBar(
      title: const Text('屏幕适配'),
    ),
    body: Center(
      child: Container(
        width: Adapt.setPx(300),
        height: Adapt.setPx(300),
        color: Colors.orange,
        alignment: Alignment.center,
        child: Text(
          'Hello Word',
          style: TextStyle(fontSize: Adapt.setPx(30)),
          textAlign: TextAlign.center,
        ),
      ),
    ),
  );
}
Flutter屏幕适配的三种方案_第3张图片

注意:一定要在已经有 MaterialApp 的 Widget 中使用 context ,否则是无效的。我这里定义默认效果图的尺寸是 375*667,这里是可以自定义传入效果图的宽度的。

3. flutter_screenutil 插件

  • pubspec.yaml中引入

flutter_screenutil: ^5.0.1
  • 在已经有 MaterialApp 的 Widget 中使用 context 进行初始化

ScreenUtil.init(context,width:750,height:1334,allowFontScaling:false);
示例代码
Container(
   width: ScreenUtil().setWidth(300),
   height: ScreenUtil().setHeight(300)
 }
Text(
  'Hello Word',
  style: TextStyle(fontSize: ScreenUtil.getInstance().setSp(30)),
  textAlign: TextAlign.center,
)

其他更多用法可以参考官网文档:pub.flutter-io.cn/packages/fl…

你可能感兴趣的:(Android,flutter,android,ios,屏幕适配,Dart)