Flutter Widgets MediaQuery控件屏幕信息適配
MediaQuery
通常情況下,不會直接將MediaQuery當(dāng)作一個控件,而是使用MediaQuery.of獲取當(dāng)前設(shè)備的信息,用法如下:
var data = MediaQuery.of(context);
此方式必須放在MediaQuery作用域內(nèi),否則會拋出異常,MaterialApp和WidgetsApp都引入了MediaQuery,并且隨著屏幕的變化而導(dǎo)致重建,比如旋轉(zhuǎn)屏幕、彈出輸入框等。
MediaQueryData
MediaQueryData是MediaQuery.of獲取數(shù)據(jù)的類型。說明如下:
| 屬性 | 說明 |
|---|---|
| size | 邏輯像素,并不是物理像素,類似于Android中的dp,邏輯像素會在不同大小的手機(jī)上顯示的大小基本一樣,物理像素 = size*devicePixelRatio。 |
| devicePixelRatio | 單位邏輯像素的物理像素數(shù)量,即設(shè)備像素比。 |
| textScaleFactor | 單位邏輯像素字體像素數(shù),如果設(shè)置為1.5則比指定的字體大50%。 |
| platformBrightness | 當(dāng)前設(shè)備的亮度模式,比如在Android Pie手機(jī)上進(jìn)入省電模式,所有的App將會使用深色(dark)模式繪制。 |
| viewInsets | 被系統(tǒng)遮擋的部分,通常指鍵盤,彈出鍵盤,viewInsets.bottom表示鍵盤的高度。 |
| padding | 被系統(tǒng)遮擋的部分,通常指“劉海屏”或者系統(tǒng)狀態(tài)欄。 |
| viewPadding | 被系統(tǒng)遮擋的部分,通常指“劉海屏”或者系統(tǒng)狀態(tài)欄,此值獨立于padding和viewInsets,它們的值從MediaQuery控件邊界的邊緣開始測量。在移動設(shè)備上,通常是全屏。 |
| systemGestureInsets | 顯示屏邊緣上系統(tǒng)“消耗”的區(qū)域輸入事件,并阻止將這些事件傳遞給應(yīng)用。比如在Android Q手勢滑動用于頁面導(dǎo)航(ios也一樣),比如左滑退出當(dāng)前頁面。 |
| physicalDepth | 設(shè)備的最大深度,類似于三維空間的Z軸。 |
| alwaysUse24HourFormat | 是否是24小時制。 |
| accessibleNavigation | 用戶是否使用諸如TalkBack或VoiceOver之類的輔助功能與應(yīng)用程序進(jìn)行交互,用于幫助視力有障礙的人進(jìn)行使用。 |
| invertColors | 是否支持顏色反轉(zhuǎn)。 |
| highContrast | 用戶是否要求前景與背景之間的對比度高, iOS上,方法是通過“設(shè)置”->“輔助功能”->“增加對比度”。此標(biāo)志僅在運(yùn)行iOS 13的iOS設(shè)備上更新或以上。 |
| disableAnimations | 平臺是否要求盡可能禁用或減少動畫。 |
| boldText | 平臺是否要求使用粗體。 |
| orientation | 是橫屏還是豎屏。 |
獲取設(shè)備相關(guān)信息:
import 'package:demo202112/utils/common_appbar.dart';
import 'package:flutter/cupertino.dart';
import "package:flutter/material.dart";
class WyMediaQuery extends StatefulWidget {
const WyMediaQuery({Key? key}) : super(key: key);
@override
_WyMediaQueryState createState() => _WyMediaQueryState();
}
class _WyMediaQueryState extends State<WyMediaQuery> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: getAppBar('MediaQuery'),
body: MediaQuery(data: const MediaQueryData(),
child: _getDeviceMediaInfo(),),
);
}
_getDeviceMediaInfo(){
//屏幕大小
Size mSize = MediaQuery.of(context).size;
//密度
double mRatio = MediaQuery.of(context).devicePixelRatio;
//設(shè)備像素
double width = mSize.width * mRatio;
double height = mSize.height * mRatio;
// 上下邊距 (主要用于 劉海 和 內(nèi)置導(dǎo)航鍵)
double topPadding = MediaQuery.of(context).padding.top;
double bottomPadding = MediaQuery.of(context).padding.bottom;
double textScaleFactor = MediaQuery.of(context).textScaleFactor;
Brightness platformBrightness = MediaQuery.of(context).platformBrightness;
EdgeInsets viewInsets = MediaQuery.of(context).viewInsets;
EdgeInsets padding = MediaQuery.of(context).padding;
bool alwaysUse24HourFormat = MediaQuery.of(context).alwaysUse24HourFormat;
bool accessibleNavigation = MediaQuery.of(context).accessibleNavigation;
bool invertColors = MediaQuery.of(context).invertColors;
bool disableAnimations = MediaQuery.of(context).disableAnimations;
bool boldText = MediaQuery.of(context).boldText;
Orientation orientation= MediaQuery.of(context).orientation;
// bool alwaysUse24HourFormat = MediaQuery.of(context).alwaysUse24HourFormat;
return Container(
padding: EdgeInsets.all(30),
child: Column(
children: [
Text('屏幕大小:${mSize.width} x ${mSize.height}'),
Text('密度:${mRatio}'),
Text('設(shè)備像素大小:${width} x ${height}'),
Text('上邊劉海:${topPadding}'),
Text('下邊導(dǎo)航:${bottomPadding}'),
Text('textScaleFactor: ${textScaleFactor}'),
Text('platformBrightness: ${platformBrightness}'),
Text('viewInsets: ${viewInsets}'),
Text('padding: ${padding}'),
Text('alwaysUse24HourFormat: ${alwaysUse24HourFormat}'),
Text('accessibleNavigation: ${accessibleNavigation}'),
Text('invertColors: ${invertColors}'),
Text('disableAnimations: ${disableAnimations}'),
Text('boldText: ${boldText}'),
Text('orientation: ${orientation}'),
Text('orientation: ${orientation}'),
],
),);
}
}
運(yùn)行效果:


隨著屏幕旋轉(zhuǎn),設(shè)備信息跟著屏幕方向在變動。
使用場景
根據(jù)尺寸構(gòu)建不同的布局
SafeArea控件就是通過MediaQuery.of來實現(xiàn)的,平板和手機(jī)的(或者橫屏和豎屏)布局可能是不一樣的,布局判斷:
var screenSize = MediaQuery.of(context).size;
if(screenSize.width>oneColumnLayout){
//平板布局
}else{
//手機(jī)布局
}
oneColumnLayout表示一列布局的寬度。
系統(tǒng)字體變化
很多App都有一個功能就是調(diào)節(jié)字體大小,通過MediaQuery來實現(xiàn),實現(xiàn)如下:
//textScaleFactor 從1變到1.5,字體會全部增大
var _data = MediaQuery.of(context).copyWith(textScaleFactor: 1.0);
return Scaffold(
appBar: getAppBar('MediaQuery'),
body: MediaQuery(data: _data,
child: _getDeviceMediaInfo(),),
);
運(yùn)行效果:

第三方屏幕的適配框架:
flutter_screenutil:用于調(diào)整屏幕和字體大小的顫振插件。讓你的UI在不同的屏幕尺寸上顯示合理的布局!
api適配:
ScreenUtil().setWidth(540) (dart sdk>=2.6 : 540.w) //根據(jù)屏幕寬度適配尺寸
ScreenUtil().setHeight(200) (dart sdk>=2.6 : 200.h) //根據(jù)屏幕高度適配尺寸(一般根據(jù)寬度適配即可)
ScreenUtil().radius(200) (dart sdk>=2.6 : 200.r) //根據(jù)寬度或高度中的較小者進(jìn)行調(diào)整
ScreenUtil().setSp(24) (dart sdk>=2.6 : 24.sp) //適配字體
12.sm // 取12和12.sp中的最小值
ScreenUtil.pixelRatio //設(shè)備的像素密度
ScreenUtil.screenWidth (dart sdk>=2.6 : 1.sw) //設(shè)備寬度
ScreenUtil.screenHeight (dart sdk>=2.6 : 1.sh) //設(shè)備高度
ScreenUtil.bottomBarHeight //底部安全區(qū)距離,適用于全面屏下面有按鍵的
ScreenUtil.statusBarHeight //狀態(tài)欄高度 劉海屏?xí)?
ScreenUtil.textScaleFactor //系統(tǒng)字體縮放比例
ScreenUtil().scaleWidth // 實際寬度設(shè)計稿寬度的比例
ScreenUtil().scaleHeight // 實際高度與設(shè)計稿高度度的比例
ScreenUtil().orientation //屏幕方向
0.2.sw //屏幕寬度的0.2倍
0.5.sh //屏幕高度的50%
20.setVerticalSpacing // SizedBox(height: 20 * scaleHeight)
20.horizontalSpace // SizedBox(height: 20 * scaleWidth)
const RPadding.all(8) // Padding.all(8.r) - 獲取到const的優(yōu)點
REdgeInsts.all(8) // EdgeInsets.all(8.r)
EdgeInsets.only(left:8,right:8).r // EdgeInsets.only(left:8.r,right:8.r).
適配字體
//輸入字體大小(單位與初始化時的單位相同)
ScreenUtil().setSp(28)
28.sp
//例子:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'16sp, 因為設(shè)置了`textScaleFactor`,不會隨系統(tǒng)變化.',
style: TextStyle(
color: Colors.black,
fontSize: 16.sp,
),
textScaleFactor: 1.0,
),
Text(
'16sp,如果未設(shè)置,我的字體大小將隨系統(tǒng)而變化.',
style: TextStyle(
color: Colors.black,
fontSize: 16.sp,
),
),
],
)
設(shè)置字體不隨系統(tǒng)字體大小進(jìn)行改變 APP全局
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:
Text("text", textScaleFactor: 1.0)
指定的小部件:
MediaQuery( // 如果這里context不可用,你可以新建一個 [Builder] 將 [MediaQuery] 放入其中 data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), child: AnyWidget(), )
總結(jié):
本篇主要介紹了系統(tǒng)組價MediaQuery的基本參數(shù)和基本使用情況,以及擴(kuò)展第三方屏幕適配組件flutter_screenutil.
以上就是Flutter Widgets MediaQuery控件屏幕信息適配的詳細(xì)內(nèi)容,更多關(guān)于Flutter Widgets MediaQuery的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
IOS 中UIKit-UIPageControl利用delegate定位圓點位置
這篇文章主要介紹了IOS 中UIKit-UIPageControl利用delegate定位圓點位置 的相關(guān)資料,需要的朋友可以參考下2017-04-04
iOS overFullScreen與fullScreen區(qū)別分析
這篇文章主要介紹了iOS overFullScreen與fullScreen區(qū)別分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
iOS中的導(dǎo)航欄UINavigationBar與工具欄UIToolBar要點解析
UINavigation可以附著于導(dǎo)航控制器之中使用,也可以在controller中單獨使用,這里我們將來看iOS中的導(dǎo)航欄UINavigationBar與工具欄UIToolBar要點解析.2016-06-06
searchDisplayController 引起的數(shù)組越界處理辦法
這篇文章主要介紹了searchDisplayController 引起的數(shù)組越界處理辦法,需要的朋友可以參考下2015-07-07

