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

2022-09-26 18:01:43

簡介

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

更多內容請參考 http://www.flydean.com/50-flutter-mediaquery/

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

歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!