Flutter屏幕适配

Flutter屏幕适配

目前移动端的设备已经很是多,而且不一样的设备手机屏幕也不相同。前端

目前作移动端开发都要针对不一样的设备进行必定的适配,不管是移动原生开发、小程序、H5页面。vue

Flutter中如何针对不一样的手机屏幕来进行适配呢?咱们一块儿来聊聊这个话题。web

一. Flutter单位

1.1. Flutter中的单位

在进行Flutter开发时,咱们一般不须要传入尺寸的单位,那么Flutter使用的是什么单位呢?算法

  • Flutter使用的是相似于iOS中的点pt,也就是point。
  • 因此咱们常常说iPhone6的尺寸是375x667,可是它的分辨率实际上是750x1334。
  • 由于iPhone6的dpr(devicePixelRatio)是2.0,iPhone6plus的dpr是3.0
iPhone设备参数
iPhone设备参数

在Flutter开发中,咱们使用的是对应的逻辑分辨率小程序

1.2. Flutter设备信息

获取屏幕上的一些信息,能够经过MediaQuery:api

// 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. 适配概述

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

  • 在屏幕中间显示一个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),),  ),  ),  );  } } 复制代码

上面的代码在不一样屏幕上会有不一样的表现:less

  • 很明显,若是按照上面的规则,在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的对应关系

那么咱们就能够经过上面的计算方式,算出一个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适配方案
rpx适配方案

2.3. 最佳实践

若是每次咱们须要将如今的宽度或者高度,去使用HYSizeFit.setPx(200)或者HYSizeFit.setRpx(400)相似的方式去适配,显然看起来很是麻烦。

有没有更好的方案能够实现了?好比 200.px或者400.rpx,很是的清晰简洁

固然能够,咱们须要依赖Dart语言的一个特性:extension

  • Dart从2.7.0开始,能够经过extension来给现有的类进行扩展(事实上Swift里面也有)
  • 对现有的类包括:自定义的类、第三方库的类、系统的类

好比咱们如今对String类型扩展:

  • 扩展一个parseInt的方法,固然内部调用的是int.parse(this),只是调用者变成了String自己
// 步骤一:扩展代码
extension NumberParsing on String {  int parseInt() {  return int.parse(this);  }  // ··· }  // 步骤二:调用代码 // 导入扩展类对应的模块 import 'string_apis.dart'; // 使用里面的方法 print('42'.padLeft(5)); // 使用String原有的方法 print('42'.parseInt()); // 使用String扩展的方法 复制代码

显然,数字(好比200、200.0)有对应的包装类int、double,咱们能够对其进行扩展:

1.对int类型扩展

import '../shared/size_fit.dart';
 extension IntFit on int {  double get px {  return HYSizeFit.setPx(this.toDouble());  }   double get rpx {  return HYSizeFit.setRpx(this.toDouble());  } } 复制代码

2.对double类型扩展

import '../shared/size_fit.dart';
 extension DoubleFit on double {  double get px {  return HYSizeFit.setPx(this);  }   double get rpx {  return HYSizeFit.setRpx(this);  } } 复制代码

如何使用了?

import './extension/double_extension.dart';
import './extension/int_extension.dart';  print(200.px); // 在不一样屏幕下200px是不一样的值 print(400.rpx); // 在不一样屏幕下400rpx是不一样的值 复制代码

备注:全部内容首发于公众号,以后除了Flutter也会更新其余技术文章,TypeScript、React、Node、uniapp、mpvue、数据结构与算法等等,也会更新一些本身的学习心得等,欢迎你们关注

公众号
公众号
相关文章
相关标签/搜索