天天看點

flutter系列之:查詢裝置資訊的利器:MediaQuery

目錄

  • ​​簡介​​
  • ​​MediaQuery詳解​​
  • ​​MediaQuery的屬性​​
  • ​​MediaQuery的構造函數​​
  • ​​MediaQuery的使用​​
  • ​​總結​​

簡介

移動的開發中,大家可能最頭疼的就是不同裝置的規格了,現在裝置這麼多,如何才能在諸多的裝置中找到合适的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。

最通俗的解讀,最深刻的幹貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!

繼續閱讀