移動的開發中,大家可能最頭疼的就是不同裝置的規格了,現在裝置這麼多,如何才能在諸多的裝置中找到合適的widget的位置來進行繪製呢?
不用怕,在flutter中為我們提供了一個叫做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的自有屬性只有兩個,分別是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.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最常見的用處就是來判斷裝置的大小,從而根據不同裝置的大小來進行頁面的調整。
比如下面的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/
最通俗的解讀,最深刻的乾貨,最簡潔的教學,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!