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
还没有创建
其实我们仔细的产看MediaQuery
的fromWindow
初始化方法,我们可以发现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 插件 )