Flutter應(yīng)用框架搭建之屏幕適配詳解
因移動(dòng)設(shè)備的多樣性,特別是 Android 的碎片化嚴(yán)重,存在各種各樣的分辨率,而 Flutter 跨平臺(tái)開發(fā)又需同時(shí)支持 Android 和 iOS ,為盡可能的還原設(shè)計(jì)圖效果提升用戶體驗(yàn),屏幕適配就勢(shì)在必行了。
Flutter 暫時(shí)沒(méi)有官方的屏幕適配方案,在 Flutter 項(xiàng)目開發(fā)中目前大部分的適配方案都是通過(guò)比例來(lái)進(jìn)行適配,是一個(gè)通用的適配方法,該適配方法也在前端、Android、iOS、小程序等開發(fā)中廣泛使用。
原理
UI 設(shè)計(jì)的時(shí)候一般會(huì)按照一個(gè)固定的尺寸進(jìn)行設(shè)計(jì),如 360 x 690
,實(shí)際設(shè)備分辨率可能是 Google Pixel: 1080 x 1920
、Google Pixel XL: 1440 x 2560
、iPhone 12 Pro Max: 1284 x 2778
等等。開發(fā)時(shí)如果直接按照設(shè)計(jì)圖寫死數(shù)值則會(huì)出現(xiàn)最后實(shí)現(xiàn)的效果跟設(shè)計(jì)效果不一致的情況。這個(gè)時(shí)候就可以用比例的方式來(lái)進(jìn)行適配。
將設(shè)計(jì)圖分為固定單位并給這個(gè)單位定義一個(gè)標(biāo)識(shí),例如就叫 w
,然后通過(guò)獲取設(shè)備分辨率,使用設(shè)備真實(shí)寬度除以設(shè)計(jì)圖寬度 ,就得到了 1w
代表的真實(shí)寬度:
1w = 設(shè)備真實(shí)寬度 / 設(shè)計(jì)圖寬度
如設(shè)計(jì)圖尺寸是 360 x 690
,則寬度為 360w
,真實(shí)設(shè)備寬度為 1080 則 1w = 1080 / 360 = 3
。
根據(jù)上面的算法,得到對(duì)應(yīng)設(shè)備的 1w
的真實(shí)寬度:
Google Pixel: 1w = 1080 / 360 = 3
Google Pixel XL: 1w = 1440 / 360 = 4
iPhone 12 Pro Max: 1w = 1284 / 360 = 3.57
按照同樣的算法,可以給高度定義一個(gè)單位為 h
, 得出對(duì)應(yīng)設(shè)備的高度單位的真實(shí)值,如下:
Google Pixel: 1h = 1920 / 690 = 2.78
Google Pixel XL: 1h = 2560 / 690 = 3.71
iPhone 12 Pro Max: 1h = 2778 / 690 = 4.03
得到換算以后 w
、h
的真實(shí)值以后,開發(fā)過(guò)程中就可以使用其來(lái)設(shè)置 UI 控件的高、寬、間距等,使其最終呈現(xiàn)的效果無(wú)限接近設(shè)計(jì)圖的效果。
開發(fā)過(guò)程中一般采用寬度來(lái)進(jìn)行適配,控件高度要么自適應(yīng),要么也設(shè)置寬度的單位,然后整體高度根據(jù)內(nèi)容自適應(yīng)。但是如果有特殊需求也可以使用高度來(lái)進(jìn)行適配,比如需求要求是 banner 占屏幕的 1/4 ,或者要求內(nèi)容剛好一屏顯示,這個(gè)時(shí)候設(shè)置控件的高度時(shí)就可以采用高度單位來(lái)進(jìn)行適配。
基于上面的算法,在項(xiàng)目中就可以實(shí)現(xiàn)對(duì)應(yīng)的適配方案了,但本著不重復(fù)造輪子的思想,項(xiàng)目開發(fā)中可以直接使用 flutter_screenutil 這個(gè)適配庫(kù)。
flutter_screenutil
flutter_screenutil
就是基于上述比例適配原理而實(shí)現(xiàn)的屏幕適配庫(kù)。 目前最新版本是 5.0.1,在 GitHub 上擁有 2.8k 的 star 。在 pub.dev 上擁有1536 個(gè) like ,130 的 pub 指數(shù), 99% 的人氣,說(shuō)明這是一個(gè)靠譜的輪子。
flutter_screenutil:讓你的UI在不同尺寸的屏幕上都能顯示合理的布局!
添加依賴
在項(xiàng)目根目錄的 pubspec.yaml
中添加 flutter_screenutil
的依賴:
dependencies: flutter: sdk: flutter # 添加依賴 flutter_screenutil: ^5.0.1
初始化
flutter_screenutil
提供了兩種方式進(jìn)行初始化:ScreenUtilInit
方式和 ScreenUtil.init
方式。首先在使用的地方導(dǎo)入包:
import 'package:flutter_screenutil/flutter_screenutil.dart';
ScreenUtilInit
使用 ScreenUtilInit 方式進(jìn)行初始化,需要將項(xiàng)目的 MaterialApp 進(jìn)行一層包裹,然后在 builder
中返回項(xiàng)目本身的 MaterialApp ,在 ScreenUtilInit 的 designSize
參數(shù)中傳入設(shè)計(jì)圖的尺寸,實(shí)現(xiàn)如下:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ScreenUtilInit( designSize: Size(360, 690), //傳入設(shè)計(jì)圖尺寸 builder: () => MaterialApp( ... ), ); } }
ScreenUtil.init
直接使用 ScreenUtil.init
方法,傳入屏幕尺寸、設(shè)計(jì)圖尺寸和屏幕方向即可對(duì) flutter_screenutil
進(jìn)行初始化,代碼如下:
ScreenUtil.init( BoxConstraints( maxWidth: MediaQuery.of(context).size.width, //屏幕寬度 maxHeight: MediaQuery.of(context).size.height, //屏幕高度 ), designSize: const Size(360, 690), // 設(shè)計(jì)圖尺寸 orientation: Orientation.portrait); // 屏幕方向
使用這種方式只需在使用 flutter_screenutil
前進(jìn)行初始化即可,一般放在根路由即第一個(gè)頁(yè)面加載的時(shí)候進(jìn)行初始化。
注意:ScreenUtil.init
不能在 MyApp
中進(jìn)行初始化,會(huì)報(bào)如下錯(cuò)誤 No MediaQuery ancestor could be found starting from the context that was passed to MediaQuery.of(). This can happen because you have not added a WidgetsApp, CupertinoApp, or MaterialApp widget (those widgets introduce a MediaQuery), or it can happen if the context you use comes from a widget above those widgets.
因?yàn)檫@個(gè)時(shí)候還沒(méi)加載 MaterialApp
無(wú)法使用 MediaQuery.of(context ) 獲取到屏幕寬高
關(guān)于上面兩種初始化方法,flutter_screenutil
作者推薦使用第二種方式。
使用
初始化以后就可以使用 flutter_screenutil
提供的方法獲取到適配后的數(shù)值進(jìn)行使用了。
可通過(guò)如下 api 獲取寬高以及字體的適配數(shù)值:
ScreenUtil().setWidth(540) //根據(jù)屏幕寬度適配尺寸 ScreenUtil().setHeight(200) //根據(jù)屏幕高度適配尺寸(一般根據(jù)寬度適配即可) ScreenUtil().radius(200) //根據(jù)寬度或高度中的較小者進(jìn)行調(diào)整 ScreenUtil().setSp(24) //字體大小適配
傳入的參數(shù)即為設(shè)計(jì)圖上的大小。在實(shí)際使用中的示例如下:
Container( width: ScreenUtil().setWidth(200), height: ScreenUtil().setHeight(540), child: Text("Hello", style: TextStyle(fontSize: ScreenUtil().setSp(24)),), );
這樣即可使用適配的數(shù)值進(jìn)行開發(fā)。
但發(fā)現(xiàn)這樣寫太麻煩了,為了獲取一個(gè)適配的數(shù)值,要寫一串的很長(zhǎng)的代碼。flutter_screenutil
提供了更簡(jiǎn)潔的調(diào)用方法,使用 Dart 擴(kuò)展為 num 類型擴(kuò)展了一系列屬性可以方便開發(fā)者調(diào)用,上面的 api 可以通過(guò)擴(kuò)展屬性進(jìn)行如下轉(zhuǎn)換:
ScreenUtil().setWidth(540) => 540.h ScreenUtil().setHeight(200) => 200.w ScreenUtil().radius(200) => 200.r ScreenUtil().setSp(24) => 24.sp
修改后的使用示例如下:
Container( width: 200.w, height: 540.h, child: Text("Hello", style: TextStyle(fontSize: 24.sp),), );
這樣就簡(jiǎn)潔多了。
注意:根據(jù)前面講解的適配原理知道,一般情況下 1.w != 1.h
,除非剛好屏幕分辨率比例與設(shè)計(jì)圖比例一致,所以如果要設(shè)置正方形,切記使用相同的單位,如都設(shè)置相同的 w 或者 h ,否則可能顯示為長(zhǎng)方形。
除了上面 4 種擴(kuò)展屬性以外,還提供了 sm
以及 sw
、 sh
sm
:取數(shù)值本身與sp
的值最小的值,如12.sm
則取12
與12.sp
的值進(jìn)行比較,取最小的值。sw
:screen width 的縮寫,即屏幕寬度,作用是按屏幕寬度比例返回值。如0.2.sw
則返回屏幕寬度的 20%,1.sw
則是整個(gè)屏幕寬度sh
:screen height 的縮寫,及屏幕高度,作用與 sw 類似,返回指定比例的屏幕高度值。如1.sh
為整個(gè)屏幕高度
使用 sp
作為字體單位,默認(rèn)是會(huì)隨著系統(tǒng)字體縮放進(jìn)行變化,如果不想字體隨著系統(tǒng)縮放而變化,可設(shè)置 textScaleFactor
為 1.0
來(lái)實(shí)現(xiàn)。項(xiàng)目中可對(duì) MaterialApp
進(jìn)行全局設(shè)置或者對(duì) Text
進(jìn)行單獨(dú)設(shè)置:
全局設(shè)置:
MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter_ScreenUtil', theme: ThemeData( primarySwatch: Colors.blue, ), builder: (context, widget) { return MediaQuery( ///設(shè)置文字大小不隨系統(tǒng)設(shè)置改變 data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), child: widget, ); }, home: HomePage(title: 'FlutterScreenUtil Demo'), ),
Text 單獨(dú)設(shè)置:
Text("text", textScaleFactor: 1.0)
效果
附上官方效果圖:
其他 Api
除了適配的 api 以外,flutter_screenutil
還提供了很多實(shí)用的 api ,如下 :
ScreenUtil().pixelRatio
:設(shè)備的像素密度ScreenUtil().screenWidth
:屏幕寬度,等同于1.sw
ScreenUtil().screenHeight
:屏幕高度,等同于1.sh
ScreenUtil().bottomBarHeight
:底部導(dǎo)航高度,如全屏底部按鍵的高度ScreenUtil().statusBarHeight
:狀態(tài)欄高度ScreenUtil().textScaleFactor
:系統(tǒng)字體縮放比例ScreenUtil().scaleWidth
:實(shí)際寬度與設(shè)計(jì)圖寬度的比例ScreenUtil().scaleHeight
:實(shí)際高度與設(shè)計(jì)圖高度的比例ScreenUtil().orientation
:屏幕方向
到此這篇關(guān)于Flutter應(yīng)用框架搭建之屏幕適配詳解的文章就介紹到這了,更多相關(guān)Flutter屏幕適配內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android實(shí)現(xiàn)懸浮窗全系統(tǒng)版本
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)懸浮窗全系統(tǒng)版本,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11Android模仿Toast實(shí)現(xiàn)提示框效果
這篇文章主要為大家詳細(xì)介紹了Android模仿Toast實(shí)現(xiàn)提示框效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Android中的應(yīng)用認(rèn)領(lǐng)總結(jié)
這篇文章主要介紹了Android中的應(yīng)用認(rèn)領(lǐng)總結(jié),本文講解了如何認(rèn)領(lǐng)、對(duì)未簽名包簽名、需要替換的簽名值、驗(yàn)證簽名等內(nèi)容,需要的朋友可以參考下2015-01-01Android編程實(shí)現(xiàn)屏幕自適應(yīng)方向尺寸與分辨率的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)屏幕自適應(yīng)方向尺寸與分辨率的方法,涉及Android屏幕分辨率、布局、橫豎屏切換等相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-12-12Android App支付系列(一):微信支付接入詳細(xì)指南(附官方支付demo)
這篇文章主要介紹了Android App支付系列(一):微信支付接入詳細(xì)指南(附官方支付demo) ,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11Android自定義控件實(shí)現(xiàn)通用驗(yàn)證碼輸入框(二)
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)通用驗(yàn)證碼輸入框的第二篇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01Android 編輯頭像功能簡(jiǎn)單實(shí)現(xiàn)實(shí)例(圖片選取,裁剪)
這篇文章主要介紹了Android 編輯頭像功能簡(jiǎn)單實(shí)現(xiàn)實(shí)例(圖片選取,裁剪),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-06-06android真機(jī)調(diào)試時(shí)無(wú)法顯示logcat信息的解決方法介紹
以下是對(duì)android真機(jī)調(diào)試時(shí)無(wú)法顯示logcat信息的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下2013-07-07android Textview文字監(jiān)控(Textview使用方法)
以手機(jī)號(hào)充值為例,當(dāng)用戶輸入最后一位數(shù)時(shí)候,進(jìn)行匯率的變換,本文就實(shí)現(xiàn)類似這樣的功能2013-11-11