山在山在 發表於 2022-11-9 15:23:36

Flutter Widgets MediaQuery控件屏幕信息适配

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>MediaQuery</li><li>MediaQueryData</li><li>使用场景</li><ul class="second_class_ul"><li>根据尺寸构建不同的布局</li></ul><li>系统字体变化</li><ul class="second_class_ul"></ul><li>第三方屏幕的适配框架:</li><ul class="second_class_ul"><li>设置字体不随系统字体大小进行改变 APP全局</li></ul><li>总结:</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>MediaQuery</h2>
<p>通常情况下,不会直接将MediaQuery当作一个控件,而是使用<code>MediaQuery.of</code>获取当前设备的信息,用法如下:</p>
<div class="jb51code"><pre class="brush:cpp;">var data = MediaQuery.of(context);
</pre></div>
<p>此方式必须放在MediaQuery作用域内,否则会抛出异常,MaterialApp和WidgetsApp都引入了MediaQuery,并且随着屏幕的变化而导致重建,比如旋转屏幕、弹出输入框等。</p>
<p class="maodian"></p><h2>MediaQueryData</h2>
<p>MediaQueryData是<code>MediaQuery.of</code>获取数据的类型。说明如下:</p>
<table><tbody><tr><th>属性</th><th>说明</th></tr><tr><td>size</td><td>逻辑像素,并不是物理像素,类似于Android中的dp,逻辑像素会在不同大小的手机上显示的大小基本一样,物理像素 = size*devicePixelRatio。</td></tr><tr><td>devicePixelRatio</td><td>单位逻辑像素的物理像素数量,即设备像素比。</td></tr><tr><td>textScaleFactor</td><td>单位逻辑像素字体像素数,如果设置为1.5则比指定的字体大50%。</td></tr><tr><td>platformBrightness</td><td>当前设备的亮度模式,比如在Android Pie手机上进入省电模式,所有的App将会使用深色(dark)模式绘制。</td></tr><tr><td>viewInsets</td><td>被系统遮挡的部分,通常指键盘,弹出键盘,viewInsets.bottom表示键盘的高度。</td></tr><tr><td>padding</td><td>被系统遮挡的部分,通常指&ldquo;刘海屏&rdquo;或者系统状态栏。</td></tr><tr><td>viewPadding</td><td>被系统遮挡的部分,通常指&ldquo;刘海屏&rdquo;或者系统状态栏,此值独立于padding和viewInsets,它们的值从MediaQuery控件边界的边缘开始测量。在移动设备上,通常是全屏。</td></tr><tr><td>systemGestureInsets</td><td>显示屏边缘上系统&ldquo;消耗&rdquo;的区域输入事件,并阻止将这些事件传递给应用。比如在Android Q手势滑动用于页面导航(ios也一样),比如左滑退出当前页面。</td></tr><tr><td>physicalDepth</td><td>设备的最大深度,类似于三维空间的Z轴。</td></tr><tr><td>alwaysUse24HourFormat</td><td>是否是24小时制。</td></tr><tr><td>accessibleNavigation</td><td>用户是否使用诸如TalkBack或VoiceOver之类的辅助功能与应用程序进行交互,用于帮助视力有障碍的人进行使用。</td></tr><tr><td>invertColors</td><td>是否支持颜色反转。</td></tr><tr><td>highContrast</td><td>用户是否要求前景与背景之间的对比度高, iOS上,方法是通过&ldquo;设置&rdquo;-&gt;&ldquo;辅助功能&rdquo;-&gt;&ldquo;增加对比度&rdquo;。此标志仅在运行iOS 13的iOS设备上更新或以上。</td></tr><tr><td>disableAnimations</td><td>平台是否要求尽可能禁用或减少动画。</td></tr><tr><td>boldText</td><td>平台是否要求使用粗体。</td></tr><tr><td>orientation</td><td>是横屏还是竖屏。</td></tr></tbody></table>
<p>获取设备相关信息:</p>
<div class="jb51code"><pre class="brush:cpp;">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() =&gt; _WyMediaQueryState();
}
class _WyMediaQueryState extends State&lt;WyMediaQuery&gt; {
@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;
    //设备像素
    double width = mSize.width * mRatio;
    double height = mSize.height * mRatio;
    // 上下边距 (主要用于 刘海和内置导航键)
    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('设备像素大小:${width} x ${height}'),
      Text('上边刘海:${topPadding}'),
      Text('下边导航:${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}'),
      ],
    ),);
}
}
</pre></div>
<p>运行效果:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202211/20221109091919049.jpg" /></p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202211/20221109091919050.jpg" /></p>
<p>随着屏幕旋转,设备信息跟着屏幕方向在变动。</p>
<p class="maodian"></p><h2>使用场景</h2>
<p class="maodian"></p><h3>根据尺寸构建不同的布局</h3>
<p>SafeArea控件就是通过<code>MediaQuery.of</code>来实现的,平板和手机的(或者横屏和竖屏)布局可能是不一样的,布局判断:</p>
<div class="jb51code"><pre class="brush:cpp;">var screenSize = MediaQuery.of(context).size;
if(screenSize.width&gt;oneColumnLayout){
//平板布局
}else{
//手机布局
}
</pre></div>
<p><code>oneColumnLayout</code>表示一列布局的宽度。</p>
<p class="maodian"></p><h2>系统字体变化</h2>
<p>很多App都有一个功能就是调节字体大小,通过MediaQuery来实现,实现如下:</p>
<div class="jb51code"><pre class="brush:cpp;">//textScaleFactor 从1变到1.5,字体会全部增大
    var _data = MediaQuery.of(context).copyWith(textScaleFactor: 1.0);
    return Scaffold(
      appBar: getAppBar('MediaQuery'),
      body: MediaQuery(data: _data,
      child: _getDeviceMediaInfo(),),
    );
</pre></div>
<p>运行效果:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202211/20221109091919051.jpg" /></p>
<p class="maodian"></p><h2>第三方屏幕的适配框架:</h2>
<p>flutter_screenutil:用于调整屏幕和字体大小的颤振插件。让你的UI在不同的屏幕尺寸上显示合理的布局!</p>
<p>api适配:</p>
<div class="jb51code"><pre class="brush:cpp;">    ScreenUtil().setWidth(540)(dart sdk&gt;=2.6 : 540.w)   //根据屏幕宽度适配尺寸
    ScreenUtil().setHeight(200) (dart sdk&gt;=2.6 : 200.h)   //根据屏幕高度适配尺寸(一般根据宽度适配即可)
    ScreenUtil().radius(200)    (dart sdk&gt;=2.6 : 200.r)   //根据宽度或高度中的较小者进行调整
    ScreenUtil().setSp(24)      (dart sdk&gt;=2.6 : 24.sp)   //适配字体
    12.sm   // 取12和12.sp中的最小值
    ScreenUtil.pixelRatio       //设备的像素密度
    ScreenUtil.screenWidth   (dart sdk&gt;=2.6 : 1.sw)   //设备宽度
    ScreenUtil.screenHeight(dart sdk&gt;=2.6 : 1.sh)   //设备高度
    ScreenUtil.bottomBarHeight//底部安全区距离,适用于全面屏下面有按键的
    ScreenUtil.statusBarHeight//状态栏高度 刘海屏会更高
    ScreenUtil.textScaleFactor //系统字体缩放比例
    ScreenUtil().scaleWidth// 实际宽度设计稿宽度的比例
    ScreenUtil().scaleHeight // 实际高度与设计稿高度度的比例
    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的优点
    REdgeInsts.all(8)       // EdgeInsets.all(8.r)
    EdgeInsets.only(left:8,right:8).r // EdgeInsets.only(left:8.r,right:8.r).
</pre></div>
<p><strong>适配字体</strong></p>
<div class="jb51code"><pre class="brush:cpp;">//输入字体大小(单位与初始化时的单位相同)
ScreenUtil().setSp(28)
28.sp
//例子:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: &lt;Widget&gt;[
    Text(
      '16sp, 因为设置了`textScaleFactor`,不会随系统变化.',
      style: TextStyle(
      color: Colors.black,
      fontSize: 16.sp,
      ),
      textScaleFactor: 1.0,
    ),
    Text(
      '16sp,如果未设置,我的字体大小将随系统而变化.',
      style: TextStyle(
      color: Colors.black,
      fontSize: 16.sp,
      ),
    ),
],
)
</pre></div>
<p class="maodian"></p><h3>设置字体不随系统字体大小进行改变 APP全局</h3>
<div class="jb51code"><pre class="brush:cpp;">       MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter_ScreenUtil',
      theme: ThemeData(
          primarySwatch: Colors.blue,
      ),
      builder: (context, widget) {
          return MediaQuery(
            ///设置文字大小不随系统设置改变
            data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
            child: widget,
          );
      },
      home: HomePage(title: 'FlutterScreenUtil Demo'),
      ),
</pre></div>
<p>单独的Text:</p>
<div class="jb51code"><pre class="brush:cpp;">Text("text", textScaleFactor: 1.0)
</pre></div>
<p>指定的小部件:</p>
<div class="jb51code"><pre class="brush:cpp;">MediaQuery(
// 如果这里context不可用,你可以新建一个 将 放入其中
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
child: AnyWidget(),
)
</pre></div>
<p class="maodian"></p><h2>总结:</h2>
<p>本篇主要介绍了系统组价<code>MediaQuery</code>的基本参数和基本使用情况,以及扩展第三方屏幕适配组件<code>flutter_screenutil</code>.</p>
<p>以上就是Flutter Widgets MediaQuery控件屏幕信息适配的详细内容,更多关于Flutter Widgets MediaQuery的资料请关注琼殿技术社区其它相关文章!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>Flutter应用框架搭建实现屏幕适配方案详解</li><li>Flutter应用框架搭建之屏幕适配详解</li><li>Flutter 控制屏幕旋转的实现</li><li>flutter 屏幕尺寸适配和字体大小适配的实现</li><li>Flutter中获取屏幕及Widget的宽高示例代码</li><li>Flutter应用程序实现隐私屏幕示例解析</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Flutter Widgets MediaQuery控件屏幕信息适配