写点什么

flutter 系列之: 查询设备信息的利器:MediaQuery

作者:程序那些事
  • 2022 年 6 月 16 日
  • 本文字数:2758 字

    阅读完需:约 9 分钟

简介

移动的开发中,大家可能最头疼的就是不同设备的规格了,现在设备这么多,如何才能在诸多的设备中找到合适的 widget 的位置来进行绘制呢?


不用怕,在 flutter 中为我们提供了一个叫做 MediaQuery 的利器,大家一起来看看吧。

MediaQuery 详解

MediaQuery 从名字上来看,它的意思是媒体查询。它可以查询的东西就多了,可以查询当前你 app 的窗口信息,查询你指定的某个 widget 的信息等等,非常的强大。


我们先来看下 MediaQuery 到底是什么。 具体来说 MediaQuery 继承自 InheritedWidget:


class MediaQuery extends InheritedWidget 
复制代码


那么什么是 InheritedWidget 呢?为什么 MediaQuery 需要继承 InheritedWidget 呢?


很多时候,我们需要从 widget 的子 widget 中获取到父 widget 对象,InheritedWidget 就是一个可以提供简单获取方法的对象。


在 InheritedWidget 中可以实现 of 方法,通过调用 BuildContext.dependOnInheritedWidgetOfExactType 来从 context 中获取最临近的 InheritedWidget 对象。


这里,因为 MediaQuery 是一个媒体查询工具,所以我们可能需要在很多地方随时随地的进行对象的获取,那么这里使用 InheritedWidget 就是再好不过了。

MediaQuery 的属性

MediaQuery 的自有属性只有两个,分别是 MediaQueryData 类型的 data 和 Widget 类型的 child。


MediaQueryData 是一个类似于结构体的类,用来存储各种 Media 的状态信息。


我们先来看下 MediaQueryData 的构造函数:


const MediaQueryData({    this.size = Size.zero,    this.devicePixelRatio = 1.0,    this.textScaleFactor = 1.0,    this.platformBrightness = Brightness.light,    this.padding = EdgeInsets.zero,    this.viewInsets = EdgeInsets.zero,    this.systemGestureInsets = EdgeInsets.zero,    this.viewPadding = EdgeInsets.zero,    this.alwaysUse24HourFormat = false,    this.accessibleNavigation = false,    this.invertColors = false,    this.highContrast = false,    this.disableAnimations = false,    this.boldText = false,    this.navigationMode = NavigationMode.traditional,  })
复制代码


可以看到,MediaQueryData 中包含了很多有用的属性,我们来详细看一下具体的内容。


首先是表示 media logical pixels 大小的 size。大家要注意的是,这里的 size 表示的是逻辑 pixels 的大小。


有 logical pixels,就有 Physical pixels,前者表示的逻辑大小,在任何设备上都是一样的,而后者表示的是真实的物理设备所支持的像素大小。这两种是可以不同的。一个物理像素可能代表多个逻辑像素,这个对应关系就是由 devicePixelRatio 这个属性来决定的。


devicePixelRatio 表示的是一个物理像素代表多少个逻辑像素。devicePixelRatio 并不要求是整数,比如在 Nexus 6 中,这个 devicePixelRatio=3.5。


接下来是 textScaleFactor,表示一个逻辑像素能够表示多少个字体像素。或者你可以将其理解为字体的放大程度。


比如 textScaleFactor=1.5,那么它的意思是呈现出来的字体要比给定的字体大 50%。


然后是 platformBrightness,表示的是设备的明亮程度。最常见的比如说明亮模式或者黑暗模式等。


viewInsets 指的是被系统 UI 所完全遮罩的部分,比如说我们在进行键盘输入的时候,会弹起键盘界面。


padding 表示的是被系统 UI 所部分遮罩,并不能完全看见的部分,通常是系统状态栏,比如 iphone 中的刘海等。


viewPadding 表示的是被系统 UI 所部分遮罩,并不能完全看见的部分,通常是系统状态栏,比如 iphone 中的刘海等。


哇喔,看起来 padding 和 viewPadding 是一样的,那么事实是否如此呢?


这两者通常情况下是一样的,只有在出现键盘输入界面的时候两者就会发生不同。


简单来说,viewPadding 是固定的,它的大小不会随键盘的显示而发生变化,Padding 是可变化的,当键盘弹起,系统状态栏被遮罩的时候,它的 bottom 值就是 0。


systemGestureInsets 是一个特殊的手势区域,在这个区域里面只能识别部分的手势指令,而不能识别所有的手势指令,所以需要这样的一个属性。


alwaysUse24HourFormat 表示是否使用 24 小时的时间格式。


accessibleNavigation 表示用户是否使用了一些 accessibility 服务来和应用进行交互。


还有其他的一些属性比如 highContrast,disableAnimations,boldText,navigationMode 和 orientation 等基础的属性可以使用。


MediaQuery 的另外一个属性就是 child 了。

MediaQuery 的构造函数

MediaQuery 除了最常规的构造函数之外,还有三个构造函数,分别是 MediaQuery.removePadding,MediaQuery.removeViewInsets 和 MediaQuery.removeViewPadding。


这三个构造函数都是通过传入一个指定的 context 和 child 来构造 MediaQuery,但是他们都相应的移出了一些属性。根据名字就可以看出来,这三个分别移出的是 padding,viewInsets 和 viewPadding。


我们以 removePadding 为例,看一下具体的实现流程:


  factory MediaQuery.removePadding({    Key? key,    required BuildContext context,    bool removeLeft = false,    bool removeTop = false,    bool removeRight = false,    bool removeBottom = false,    required Widget child,  }) {    return MediaQuery(      key: key,      data: MediaQuery.of(context).removePadding(        removeLeft: removeLeft,        removeTop: removeTop,        removeRight: removeRight,        removeBottom: removeBottom,      ),      child: child,    );  }
复制代码


removePadding 方法需要传入四个额外的参数来表示是否需要移出 padding 的 left,top,right 或者 bottom。


我们可以看到返回了一个新的 MediaQuery,其中 data 部分使用了MediaQuery.of(context)来获取 context 最近的 MediaQuery,然后调用它的 removePadding 方法将对应的 padding 属性删除。

MediaQuery 的使用

讲完 MediaQuery 的构造函数,接下来我们看一下 MediaQuery 常用的使用场景。


其实 MediaQuery 最常见的用处就是来判断设备的大小,从而根据不同设备的大小来进行页面的调整。


比如下面的 getSize 方法:


enum ScreenSize { Small, Normal, Large, ExtraLarge }
ScreenSize getSize(BuildContext context) { double deviceWidth = MediaQuery.of(context).size.shortestSide; if (deviceWidth > 900) return ScreenSize.ExtraLarge; if (deviceWidth > 600) return ScreenSize.Large; if (deviceWidth > 300) return ScreenSize.Normal; return ScreenSize.Small;}
复制代码


我们通过MediaQuery.of(context)拿到 MediaQuery,然后通过 size 的 shortestSide 属性获得设备的宽度,然后根据设备的宽度跟特定的宽度进行对比,从而判断设备屏幕的大小。


当然,MediaQuery 还可以用在其他需要检测 Media 属性的地方,大家可以仔细体会。

总结

MediaQuery 是 flutter 中一个非常方便的工具,用来检测 media 的属性情况,根据 MediaQuery,我们可以做出更加富有交互性的 APP。

发布于: 刚刚阅读数: 3
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
flutter系列之:查询设备信息的利器:MediaQuery_flutter_程序那些事_InfoQ写作社区