目前移動端的設備已經非常多伍伤,并且不同的設備手機屏幕也不相同。
目前做移動端開發(fā)都要針對不同的設備進行一定的適配遣钳,無論是移動原生開發(fā)扰魂、小程序、H5頁面蕴茴。
Flutter中如何針對不同的手機屏幕來進行適配呢劝评?我們一起來聊聊這個話題。
一. Flutter單位
1.1. Flutter中的單位
在進行Flutter開發(fā)時倦淀,我們通常不需要傳入尺寸的單位蒋畜,那么Flutter使用的是什么單位呢?
- Flutter使用的是類似于iOS中的點pt撞叽,也就是point百侧。
- 所以我們經常說iPhone6的尺寸是375x667,但是它的分辨率其實是750x1334能扒。
- 因為iPhone6的dpr(devicePixelRatio)是2.0佣渴,iPhone6plus的dpr是3.0
在Flutter開發(fā)中,我們使用的是對應的邏輯分辨率
1.2. Flutter設備信息
獲取屏幕上的一些信息初斑,可以通過MediaQuery:
// 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.狀態(tài)欄的高度
// 有劉海的屏幕:44 沒有劉海的屏幕為20
final statusBarHeight = mediaQueryData.padding.top;
// 有劉海的屏幕:34 沒有劉海的屏幕0
final bottomHeight = mediaQueryData.padding.bottom;
print("狀態(tài)欄height: $statusBarHeight 底部高度:$bottomHeight");
獲取一些設備相關的信息辛润,可以使用官方提供的一個庫:
dependencies:
device_info: ^0.4.2+1
二. 適配方案
2.1. 適配概述
假如我們有下面這樣一段代碼:
- 在屏幕中間顯示一個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),),
),
),
);
}
}
上面的代碼在不同屏幕上會有不同的表現(xiàn):
很明顯,如果按照上面的規(guī)則见秤,在iPhone5上面砂竖,尺寸過大,在iPhone6plus上面尺寸過小
在開發(fā)中鹃答,我們應該可以根據不同的屏幕來完成尺寸的縮放
在前端開發(fā)中乎澄,針對不同的屏幕常見的適配方案有下面幾種:
rem:
rem是給根標簽(HTML標簽)設置一個字體大小测摔;
但是不同的屏幕要動畫設置不同的字體大兄眉谩(可以通過媒體查詢解恰,也可以通過js動態(tài)計算);
其它所有的單位都使用rem單位(相對于根標簽)浙于;
vw护盈、wh:
vw和vh是將屏幕(視口)分成100等份,一個1vw相當于是1%的大行咝铩腐宋;
其它所有的單位都使用vw或wh單位;
rpx:
rpx是小程序中的適配方案檀轨,它將750px作為設計稿胸竞,1rpx=屏幕寬度/750;
其它所有的單位都使用rpx單位参萄;
這里我采用小程序的rpx來完成Flutter的適配
2.2. rpx適配
小程序中rpx的原理是什么呢撤师?
- 不管是什么屏幕,統(tǒng)一分成750份
- 在iPhone5上:1rpx = 320/750 = 0.4266 ≈ 0.42px
- 在iPhone6上:1rpx = 375/750 = 0.5px
- 在iPhone6plus上:1rpx = 414/750 = 0.552px
那么我們就可以通過上面的計算方式拧揽,算出一個rpx剃盾,再將自己的size和rpx單位相乘即可:
- 比如100px的寬度:100 * 2 * rpx
- 在iPhone5上計算出的結果是84px
- 在iPhone6上計算出的結果是100px
- 在iPhone6plus上計算出的結果是110.4px
我們自己來封裝一個工具類:
工具類需要進行初始化,傳入context
可以通過傳入context淤袜,利用媒體查詢獲取屏幕的寬度和高度
也可以傳入一個可選的參數(shù)痒谴,以什么尺寸作為設計稿
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),),
),
),
);
}
}
我們來看一下實現(xiàn)效果:
屏幕適配也可以使用第三方庫:flutter_screenutil
參考:小碼哥Flutter