1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'dart:math' as math; |
6 | import 'dart:ui' as ui; |
7 | |
8 | import 'package:flutter/foundation.dart'; |
9 | import 'package:flutter/gestures.dart'; |
10 | |
11 | import 'basic.dart'; |
12 | import 'binding.dart'; |
13 | import 'debug.dart'; |
14 | import 'framework.dart'; |
15 | import 'inherited_model.dart'; |
16 | |
17 | // Examples can assume: |
18 | // late BuildContext context; |
19 | |
20 | /// Whether in portrait or landscape. |
21 | enum Orientation { |
22 | /// Taller than wide. |
23 | portrait, |
24 | |
25 | /// Wider than tall. |
26 | landscape |
27 | } |
28 | |
29 | /// Specifies a part of MediaQueryData to depend on. |
30 | /// |
31 | /// [MediaQuery] contains a large number of related properties. Widgets frequently |
32 | /// depend on only a few of these attributes. For example, a widget that needs to |
33 | /// rebuild when the [MediaQueryData.textScaler] changes does not need to be |
34 | /// notified when the [MediaQueryData.size] changes. Specifying an aspect avoids |
35 | /// unnecessary rebuilds. |
36 | enum _MediaQueryAspect { |
37 | /// Specifies the aspect corresponding to [MediaQueryData.size]. |
38 | size, |
39 | /// Specifies the aspect corresponding to [MediaQueryData.orientation]. |
40 | orientation, |
41 | /// Specifies the aspect corresponding to [MediaQueryData.devicePixelRatio]. |
42 | devicePixelRatio, |
43 | /// Specifies the aspect corresponding to [MediaQueryData.textScaleFactor]. |
44 | textScaleFactor, |
45 | /// Specifies the aspect corresponding to [MediaQueryData.textScaler]. |
46 | textScaler, |
47 | /// Specifies the aspect corresponding to [MediaQueryData.platformBrightness]. |
48 | platformBrightness, |
49 | /// Specifies the aspect corresponding to [MediaQueryData.padding]. |
50 | padding, |
51 | /// Specifies the aspect corresponding to [MediaQueryData.viewInsets]. |
52 | viewInsets, |
53 | /// Specifies the aspect corresponding to [MediaQueryData.systemGestureInsets]. |
54 | systemGestureInsets, |
55 | /// Specifies the aspect corresponding to [MediaQueryData.viewPadding]. |
56 | viewPadding, |
57 | /// Specifies the aspect corresponding to [MediaQueryData.alwaysUse24HourFormat]. |
58 | alwaysUse24HourFormat, |
59 | /// Specifies the aspect corresponding to [MediaQueryData.accessibleNavigation]. |
60 | accessibleNavigation, |
61 | /// Specifies the aspect corresponding to [MediaQueryData.invertColors]. |
62 | invertColors, |
63 | /// Specifies the aspect corresponding to [MediaQueryData.highContrast]. |
64 | highContrast, |
65 | /// Specifies the aspect corresponding to [MediaQueryData.onOffSwitchLabels]. |
66 | onOffSwitchLabels, |
67 | /// Specifies the aspect corresponding to [MediaQueryData.disableAnimations]. |
68 | disableAnimations, |
69 | /// Specifies the aspect corresponding to [MediaQueryData.boldText]. |
70 | boldText, |
71 | /// Specifies the aspect corresponding to [MediaQueryData.navigationMode]. |
72 | navigationMode, |
73 | /// Specifies the aspect corresponding to [MediaQueryData.gestureSettings]. |
74 | gestureSettings, |
75 | /// Specifies the aspect corresponding to [MediaQueryData.displayFeatures]. |
76 | displayFeatures, |
77 | } |
78 | |
79 | /// Information about a piece of media (e.g., a window). |
80 | /// |
81 | /// For example, the [MediaQueryData.size] property contains the width and |
82 | /// height of the current window. |
83 | /// |
84 | /// To obtain individual attributes in a [MediaQueryData], prefer to use the |
85 | /// attribute-specific functions of [MediaQuery] over obtaining the entire |
86 | /// [MediaQueryData] and accessing its members. |
87 | /// {@macro flutter.widgets.media_query.MediaQuery.useSpecific} |
88 | /// |
89 | /// To obtain the entire current [MediaQueryData] for a given [BuildContext], |
90 | /// use the [MediaQuery.of] function. This can be useful if you are going to use |
91 | /// [copyWith] to replace the [MediaQueryData] with one with an updated |
92 | /// property. |
93 | /// |
94 | /// ## Insets and Padding |
95 | /// |
96 | /// ![A diagram of padding, viewInsets, and viewPadding in correlation with each |
97 | /// other](https://flutter.github.io/assets-for-api-docs/assets/widgets/media_query.png) |
98 | /// |
99 | /// This diagram illustrates how [padding] relates to [viewPadding] and |
100 | /// [viewInsets], shown here in its simplest configuration, as the difference |
101 | /// between the two. In cases when the viewInsets exceed the viewPadding, like |
102 | /// when a software keyboard is shown below, padding goes to zero rather than a |
103 | /// negative value. Therefore, padding is calculated by taking |
104 | /// `max(0.0, viewPadding - viewInsets)`. |
105 | /// |
106 | /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/widgets/window_padding.mp4} |
107 | /// |
108 | /// In this diagram, the black areas represent system UI that the app cannot |
109 | /// draw over. The red area represents view padding that the application may not |
110 | /// be able to detect gestures in and may not want to draw in. The grey area |
111 | /// represents the system keyboard, which can cover over the bottom view padding |
112 | /// when visible. |
113 | /// |
114 | /// MediaQueryData includes three [EdgeInsets] values: |
115 | /// [padding], [viewPadding], and [viewInsets]. These values reflect the |
116 | /// configuration of the device and are used and optionally consumed by widgets |
117 | /// that position content within these insets. The padding value defines areas |
118 | /// that might not be completely visible, like the display "notch" on the iPhone |
119 | /// X. The viewInsets value defines areas that aren't visible at all, typically |
120 | /// because they're obscured by the device's keyboard. Similar to viewInsets, |
121 | /// viewPadding does not differentiate padding in areas that may be obscured. |
122 | /// For example, by using the viewPadding property, padding would defer to the |
123 | /// iPhone "safe area" regardless of whether a keyboard is showing. |
124 | /// |
125 | /// {@youtube 560 315 https://www.youtube.com/watch?v=ceCo8U0XHqw} |
126 | /// |
127 | /// The viewInsets and viewPadding are independent values, they're |
128 | /// measured from the edges of the MediaQuery widget's bounds. Together they |
129 | /// inform the [padding] property. The bounds of the top level MediaQuery |
130 | /// created by [WidgetsApp] are the same as the window that contains the app. |
131 | /// |
132 | /// Widgets whose layouts consume space defined by [viewInsets], [viewPadding], |
133 | /// or [padding] should enclose their children in secondary MediaQuery |
134 | /// widgets that reduce those properties by the same amount. |
135 | /// The [removePadding], [removeViewPadding], and [removeViewInsets] methods are |
136 | /// useful for this. |
137 | /// |
138 | /// See also: |
139 | /// |
140 | /// * [Scaffold], [SafeArea], [CupertinoTabScaffold], and |
141 | /// [CupertinoPageScaffold], all of which are informed by [padding], |
142 | /// [viewPadding], and [viewInsets]. |
143 | @immutable |
144 | class MediaQueryData { |
145 | /// Creates data for a media query with explicit values. |
146 | /// |
147 | /// In a typical application, calling this constructor directly is rarely |
148 | /// needed. Consider using [MediaQueryData.fromView] to create data based on a |
149 | /// [dart:ui.FlutterView], or [MediaQueryData.copyWith] to create a new copy |
150 | /// of [MediaQueryData] with updated properties from a base [MediaQueryData]. |
151 | const MediaQueryData({ |
152 | this.size = Size.zero, |
153 | this.devicePixelRatio = 1.0, |
154 | @Deprecated( |
155 | 'Use textScaler instead. ' |
156 | 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' |
157 | 'This feature was deprecated after v3.12.0-2.0.pre.' , |
158 | ) |
159 | double textScaleFactor = 1.0, |
160 | TextScaler textScaler = _kUnspecifiedTextScaler, |
161 | this.platformBrightness = Brightness.light, |
162 | this.padding = EdgeInsets.zero, |
163 | this.viewInsets = EdgeInsets.zero, |
164 | this.systemGestureInsets = EdgeInsets.zero, |
165 | this.viewPadding = EdgeInsets.zero, |
166 | this.alwaysUse24HourFormat = false, |
167 | this.accessibleNavigation = false, |
168 | this.invertColors = false, |
169 | this.highContrast = false, |
170 | this.onOffSwitchLabels = false, |
171 | this.disableAnimations = false, |
172 | this.boldText = false, |
173 | this.navigationMode = NavigationMode.traditional, |
174 | this.gestureSettings = const DeviceGestureSettings(touchSlop: kTouchSlop), |
175 | this.displayFeatures = const <ui.DisplayFeature>[], |
176 | }) : _textScaleFactor = textScaleFactor, |
177 | _textScaler = textScaler, |
178 | assert( |
179 | identical(textScaler, _kUnspecifiedTextScaler) || textScaleFactor == 1.0, |
180 | 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.' , |
181 | ); |
182 | |
183 | /// Deprecated. Use [MediaQueryData.fromView] instead. |
184 | /// |
185 | /// This constructor was operating on a single window assumption. In |
186 | /// preparation for Flutter's upcoming multi-window support, it has been |
187 | /// deprecated. |
188 | @Deprecated( |
189 | 'Use MediaQueryData.fromView instead. ' |
190 | 'This constructor was deprecated in preparation for the upcoming multi-window support. ' |
191 | 'This feature was deprecated after v3.7.0-32.0.pre.' |
192 | ) |
193 | factory MediaQueryData.fromWindow(ui.FlutterView window) => MediaQueryData.fromView(window); |
194 | |
195 | /// Creates data for a [MediaQuery] based on the given `view`. |
196 | /// |
197 | /// If provided, the `platformData` is used to fill in the platform-specific |
198 | /// aspects of the newly created [MediaQueryData]. If `platformData` is null, |
199 | /// the `view`'s [PlatformDispatcher] is consulted to construct the |
200 | /// platform-specific data. |
201 | /// |
202 | /// Data which is exposed directly on the [FlutterView] is considered |
203 | /// view-specific. Data which is only exposed via the |
204 | /// [FlutterView.platformDispatcher] property is considered platform-specific. |
205 | /// |
206 | /// Callers of this method should ensure that they also register for |
207 | /// notifications so that the [MediaQueryData] can be updated when any data |
208 | /// used to construct it changes. Notifications to consider are: |
209 | /// |
210 | /// * [WidgetsBindingObserver.didChangeMetrics] or |
211 | /// [dart:ui.PlatformDispatcher.onMetricsChanged], |
212 | /// * [WidgetsBindingObserver.didChangeAccessibilityFeatures] or |
213 | /// [dart:ui.PlatformDispatcher.onAccessibilityFeaturesChanged], |
214 | /// * [WidgetsBindingObserver.didChangeTextScaleFactor] or |
215 | /// [dart:ui.PlatformDispatcher.onTextScaleFactorChanged], |
216 | /// * [WidgetsBindingObserver.didChangePlatformBrightness] or |
217 | /// [dart:ui.PlatformDispatcher.onPlatformBrightnessChanged]. |
218 | /// |
219 | /// The last three notifications are only relevant if no `platformData` is |
220 | /// provided. If `platformData` is provided, callers should ensure to call |
221 | /// this method again when it changes to keep the constructed [MediaQueryData] |
222 | /// updated. |
223 | /// |
224 | /// In general, [MediaQuery.of], and its associated "...Of" methods, are the |
225 | /// appropriate way to obtain [MediaQueryData] from a widget. This `fromView` |
226 | /// constructor is primarily for use in the implementation of the framework |
227 | /// itself. |
228 | /// |
229 | /// See also: |
230 | /// |
231 | /// * [MediaQuery.fromView], which constructs [MediaQueryData] from a provided |
232 | /// [FlutterView], makes it available to descendant widgets, and sets up |
233 | /// the appropriate notification listeners to keep the data updated. |
234 | MediaQueryData.fromView(ui.FlutterView view, {MediaQueryData? platformData}) |
235 | : size = view.physicalSize / view.devicePixelRatio, |
236 | devicePixelRatio = view.devicePixelRatio, |
237 | _textScaleFactor = 1.0, // _textScaler is the source of truth. |
238 | _textScaler = _textScalerFromView(view, platformData), |
239 | platformBrightness = platformData?.platformBrightness ?? view.platformDispatcher.platformBrightness, |
240 | padding = EdgeInsets.fromViewPadding(view.padding, view.devicePixelRatio), |
241 | viewPadding = EdgeInsets.fromViewPadding(view.viewPadding, view.devicePixelRatio), |
242 | viewInsets = EdgeInsets.fromViewPadding(view.viewInsets, view.devicePixelRatio), |
243 | systemGestureInsets = EdgeInsets.fromViewPadding(view.systemGestureInsets, view.devicePixelRatio), |
244 | accessibleNavigation = platformData?.accessibleNavigation ?? view.platformDispatcher.accessibilityFeatures.accessibleNavigation, |
245 | invertColors = platformData?.invertColors ?? view.platformDispatcher.accessibilityFeatures.invertColors, |
246 | disableAnimations = platformData?.disableAnimations ?? view.platformDispatcher.accessibilityFeatures.disableAnimations, |
247 | boldText = platformData?.boldText ?? view.platformDispatcher.accessibilityFeatures.boldText, |
248 | highContrast = platformData?.highContrast ?? view.platformDispatcher.accessibilityFeatures.highContrast, |
249 | onOffSwitchLabels = platformData?.onOffSwitchLabels ?? view.platformDispatcher.accessibilityFeatures.onOffSwitchLabels, |
250 | alwaysUse24HourFormat = platformData?.alwaysUse24HourFormat ?? view.platformDispatcher.alwaysUse24HourFormat, |
251 | navigationMode = platformData?.navigationMode ?? NavigationMode.traditional, |
252 | gestureSettings = DeviceGestureSettings.fromView(view), |
253 | displayFeatures = view.displayFeatures; |
254 | |
255 | static TextScaler _textScalerFromView(ui.FlutterView view, MediaQueryData? platformData) { |
256 | final double scaleFactor = platformData?.textScaleFactor ?? view.platformDispatcher.textScaleFactor; |
257 | return scaleFactor == 1.0 ? TextScaler.noScaling : TextScaler.linear(scaleFactor); |
258 | } |
259 | |
260 | /// The size of the media in logical pixels (e.g, the size of the screen). |
261 | /// |
262 | /// Logical pixels are roughly the same visual size across devices. Physical |
263 | /// pixels are the size of the actual hardware pixels on the device. The |
264 | /// number of physical pixels per logical pixel is described by the |
265 | /// [devicePixelRatio]. |
266 | /// |
267 | /// Prefer using [MediaQuery.sizeOf] over [MediaQuery.of]`.size` to get the |
268 | /// size, since the former will only notify of changes in [size], while the |
269 | /// latter will notify for all [MediaQueryData] changes. |
270 | /// |
271 | /// For widgets drawn in an [Overlay], do not assume that the size of the |
272 | /// [Overlay] is the size of the [MediaQuery]'s size. Nested overlays can have |
273 | /// different sizes. |
274 | /// |
275 | /// ## Troubleshooting |
276 | /// |
277 | /// It is considered bad practice to cache and later use the size returned by |
278 | /// `MediaQuery.sizeOf(context)`. It will make the application non-responsive |
279 | /// and might lead to unexpected behaviors. |
280 | /// |
281 | /// For instance, during startup, especially in release mode, the first |
282 | /// returned size might be [Size.zero]. The size will be updated when the |
283 | /// native platform reports the actual resolution. Using [MediaQuery.sizeOf] |
284 | /// will ensure that when the size changes, any widgets depending on the size |
285 | /// are automatically rebuilt. |
286 | /// |
287 | /// See the article on [Creating responsive and adaptive |
288 | /// apps](https://docs.flutter.dev/development/ui/layout/adaptive-responsive) |
289 | /// for an introduction. |
290 | /// |
291 | /// See also: |
292 | /// |
293 | /// * [FlutterView.physicalSize], which returns the size of the view in physical pixels. |
294 | /// * [FlutterView.display], which returns reports display information like size, and refresh rate. |
295 | /// * [MediaQuery.sizeOf], a method to find and depend on the size defined for |
296 | /// a [BuildContext]. |
297 | final Size size; |
298 | |
299 | /// The number of device pixels for each logical pixel. This number might not |
300 | /// be a power of two. Indeed, it might not even be an integer. For example, |
301 | /// the Nexus 6 has a device pixel ratio of 3.5. |
302 | final double devicePixelRatio; |
303 | |
304 | /// Deprecated. Will be removed in a future version of Flutter. Use |
305 | /// [textScaler] instead. |
306 | /// |
307 | /// The number of font pixels for each logical pixel. |
308 | /// |
309 | /// For example, if the text scale factor is 1.5, text will be 50% larger than |
310 | /// the specified font size. |
311 | /// |
312 | /// See also: |
313 | /// |
314 | /// * [MediaQuery.textScaleFactorOf], a method to find and depend on the |
315 | /// textScaleFactor defined for a [BuildContext]. |
316 | @Deprecated( |
317 | 'Use textScaler instead. ' |
318 | 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' |
319 | 'This feature was deprecated after v3.12.0-2.0.pre.' , |
320 | ) |
321 | double get textScaleFactor => textScaler.textScaleFactor; |
322 | // TODO(LongCatIsLooong): remove this after textScaleFactor is removed. To |
323 | // maintain backward compatibility and also keep the const constructor this |
324 | // has to be kept as a private field. |
325 | // https://github.com/flutter/flutter/issues/128825 |
326 | final double _textScaleFactor; |
327 | |
328 | /// The font scaling strategy to use for laying out textual contents. |
329 | /// |
330 | /// If this [MediaQueryData] is created by the [MediaQueryData.fromView] |
331 | /// constructor, this property reflects the platform's preferred text scaling |
332 | /// strategy, and may change as the user changes the scaling factor in the |
333 | /// operating system's accessibility settings. |
334 | /// |
335 | /// See also: |
336 | /// |
337 | /// * [MediaQuery.textScalerOf], a method to find and depend on the |
338 | /// [textScaler] defined for a [BuildContext]. |
339 | /// * [TextPainter], a class that lays out and paints text. |
340 | TextScaler get textScaler { |
341 | // The constructor was called with an explicitly specified textScaler value, |
342 | // we assume the caller is migrated and ignore _textScaleFactor. |
343 | if (!identical(_kUnspecifiedTextScaler, _textScaler)) { |
344 | return _textScaler; |
345 | } |
346 | return _textScaleFactor == 1.0 |
347 | // textScaleFactor and textScaler from the constructor are consistent. |
348 | ? TextScaler.noScaling |
349 | // The constructor was called with an explicitly specified textScaleFactor, |
350 | // we assume the caller is unmigrated and ignore _textScaler. |
351 | : TextScaler.linear(_textScaleFactor); |
352 | } |
353 | final TextScaler _textScaler; |
354 | |
355 | /// The current brightness mode of the host platform. |
356 | /// |
357 | /// For example, starting in Android Pie, battery saver mode asks all apps to |
358 | /// render in a "dark mode". |
359 | /// |
360 | /// Not all platforms necessarily support a concept of brightness mode. Those |
361 | /// platforms will report [Brightness.light] in this property. |
362 | /// |
363 | /// See also: |
364 | /// |
365 | /// * [MediaQuery.platformBrightnessOf], a method to find and depend on the |
366 | /// platformBrightness defined for a [BuildContext]. |
367 | final Brightness platformBrightness; |
368 | |
369 | /// The parts of the display that are completely obscured by system UI, |
370 | /// typically by the device's keyboard. |
371 | /// |
372 | /// When a mobile device's keyboard is visible `viewInsets.bottom` |
373 | /// corresponds to the top of the keyboard. |
374 | /// |
375 | /// This value is independent of the [padding] and [viewPadding]. viewPadding |
376 | /// is measured from the edges of the [MediaQuery] widget's bounds. Padding is |
377 | /// calculated based on the viewPadding and viewInsets. The bounds of the top |
378 | /// level MediaQuery created by [WidgetsApp] are the same as the window |
379 | /// (often the mobile device screen) that contains the app. |
380 | /// |
381 | /// {@youtube 560 315 https://www.youtube.com/watch?v=ceCo8U0XHqw} |
382 | /// |
383 | /// See also: |
384 | /// |
385 | /// * [FlutterView], which provides some additional detail about this property |
386 | /// and how it relates to [padding] and [viewPadding]. |
387 | final EdgeInsets viewInsets; |
388 | |
389 | /// The parts of the display that are partially obscured by system UI, |
390 | /// typically by the hardware display "notches" or the system status bar. |
391 | /// |
392 | /// If you consumed this padding (e.g. by building a widget that envelops or |
393 | /// accounts for this padding in its layout in such a way that children are |
394 | /// no longer exposed to this padding), you should remove this padding |
395 | /// for subsequent descendants in the widget tree by inserting a new |
396 | /// [MediaQuery] widget using the [MediaQuery.removePadding] factory. |
397 | /// |
398 | /// Padding is derived from the values of [viewInsets] and [viewPadding]. |
399 | /// |
400 | /// {@youtube 560 315 https://www.youtube.com/watch?v=ceCo8U0XHqw} |
401 | /// |
402 | /// See also: |
403 | /// |
404 | /// * [FlutterView], which provides some additional detail about this |
405 | /// property and how it relates to [viewInsets] and [viewPadding]. |
406 | /// * [SafeArea], a widget that consumes this padding with a [Padding] widget |
407 | /// and automatically removes it from the [MediaQuery] for its child. |
408 | final EdgeInsets padding; |
409 | |
410 | /// The parts of the display that are partially obscured by system UI, |
411 | /// typically by the hardware display "notches" or the system status bar. |
412 | /// |
413 | /// This value remains the same regardless of whether the system is reporting |
414 | /// other obstructions in the same physical area of the screen. For example, a |
415 | /// software keyboard on the bottom of the screen that may cover and consume |
416 | /// the same area that requires bottom padding will not affect this value. |
417 | /// |
418 | /// This value is independent of the [padding] and [viewInsets]: their values |
419 | /// are measured from the edges of the [MediaQuery] widget's bounds. The |
420 | /// bounds of the top level MediaQuery created by [WidgetsApp] are the |
421 | /// same as the window that contains the app. On mobile devices, this will |
422 | /// typically be the full screen. |
423 | /// |
424 | /// {@youtube 560 315 https://www.youtube.com/watch?v=ceCo8U0XHqw} |
425 | /// |
426 | /// See also: |
427 | /// |
428 | /// * [FlutterView], which provides some additional detail about this |
429 | /// property and how it relates to [padding] and [viewInsets]. |
430 | final EdgeInsets viewPadding; |
431 | |
432 | /// The areas along the edges of the display where the system consumes |
433 | /// certain input events and blocks delivery of those events to the app. |
434 | /// |
435 | /// Starting with Android Q, simple swipe gestures that start within the |
436 | /// [systemGestureInsets] areas are used by the system for page navigation |
437 | /// and may not be delivered to the app. Taps and swipe gestures that begin |
438 | /// with a long-press are delivered to the app, but simple press-drag-release |
439 | /// swipe gestures which begin within the area defined by [systemGestureInsets] |
440 | /// may not be. |
441 | /// |
442 | /// Apps should avoid locating gesture detectors within the system gesture |
443 | /// insets area. Apps should feel free to put visual elements within |
444 | /// this area. |
445 | /// |
446 | /// This property is currently only expected to be set to a non-default value |
447 | /// on Android starting with version Q. |
448 | /// |
449 | /// {@tool dartpad} |
450 | /// For apps that might be deployed on Android Q devices with full gesture |
451 | /// navigation enabled, use [systemGestureInsets] with [Padding] |
452 | /// to avoid having the left and right edges of the [Slider] from appearing |
453 | /// within the area reserved for system gesture navigation. |
454 | /// |
455 | /// By default, [Slider]s expand to fill the available width. So, we pad the |
456 | /// left and right sides. |
457 | /// |
458 | /// ** See code in examples/api/lib/widgets/media_query/media_query_data.system_gesture_insets.0.dart ** |
459 | /// {@end-tool} |
460 | final EdgeInsets systemGestureInsets; |
461 | |
462 | /// Whether to use 24-hour format when formatting time. |
463 | /// |
464 | /// The behavior of this flag is different across platforms: |
465 | /// |
466 | /// - On Android this flag is reported directly from the user settings called |
467 | /// "Use 24-hour format". It applies to any locale used by the application, |
468 | /// whether it is the system-wide locale, or the custom locale set by the |
469 | /// application. |
470 | /// - On iOS this flag is set to true when the user setting called "24-Hour |
471 | /// Time" is set or the system-wide locale's default uses 24-hour |
472 | /// formatting. |
473 | final bool alwaysUse24HourFormat; |
474 | |
475 | /// Whether the user is using an accessibility service like TalkBack or |
476 | /// VoiceOver to interact with the application. |
477 | /// |
478 | /// When this setting is true, features such as timeouts should be disabled or |
479 | /// have minimum durations increased. |
480 | /// |
481 | /// See also: |
482 | /// |
483 | /// * [dart:ui.PlatformDispatcher.accessibilityFeatures], where the setting originates. |
484 | final bool accessibleNavigation; |
485 | |
486 | /// Whether the device is inverting the colors of the platform. |
487 | /// |
488 | /// This flag is currently only updated on iOS devices. |
489 | /// |
490 | /// See also: |
491 | /// |
492 | /// * [dart:ui.PlatformDispatcher.accessibilityFeatures], where the setting |
493 | /// originates. |
494 | final bool invertColors; |
495 | |
496 | /// Whether the user requested a high contrast between foreground and background |
497 | /// content on iOS, via Settings -> Accessibility -> Increase Contrast. |
498 | /// |
499 | /// This flag is currently only updated on iOS devices that are running iOS 13 |
500 | /// or above. |
501 | final bool highContrast; |
502 | |
503 | /// Whether the user requested to show on/off labels inside switches on iOS, |
504 | /// via Settings -> Accessibility -> Display & Text Size -> On/Off Labels. |
505 | /// |
506 | /// See also: |
507 | /// |
508 | /// * [dart:ui.PlatformDispatcher.accessibilityFeatures], where the setting |
509 | /// originates. |
510 | final bool onOffSwitchLabels; |
511 | |
512 | /// Whether the platform is requesting that animations be disabled or reduced |
513 | /// as much as possible. |
514 | /// |
515 | /// See also: |
516 | /// |
517 | /// * [dart:ui.PlatformDispatcher.accessibilityFeatures], where the setting |
518 | /// originates. |
519 | final bool disableAnimations; |
520 | |
521 | /// Whether the platform is requesting that text be drawn with a bold font |
522 | /// weight. |
523 | /// |
524 | /// See also: |
525 | /// |
526 | /// * [dart:ui.PlatformDispatcher.accessibilityFeatures], where the setting |
527 | /// originates. |
528 | final bool boldText; |
529 | |
530 | /// Describes the navigation mode requested by the platform. |
531 | /// |
532 | /// Some user interfaces are better navigated using a directional pad (DPAD) |
533 | /// or arrow keys, and for those interfaces, some widgets need to handle these |
534 | /// directional events differently. In order to know when to do that, these |
535 | /// widgets will look for the navigation mode in effect for their context. |
536 | /// |
537 | /// For instance, in a television interface, [NavigationMode.directional] |
538 | /// should be set, so that directional navigation is used to navigate away |
539 | /// from a text field using the DPAD. In contrast, on a regular desktop |
540 | /// application with the [navigationMode] set to [NavigationMode.traditional], |
541 | /// the arrow keys are used to move the cursor instead of navigating away. |
542 | /// |
543 | /// The [NavigationMode] values indicate the type of navigation to be used in |
544 | /// a widget subtree for those widgets sensitive to it. |
545 | final NavigationMode navigationMode; |
546 | |
547 | /// The gesture settings for the view this media query is derived from. |
548 | /// |
549 | /// This contains platform specific configuration for gesture behavior, |
550 | /// such as touch slop. These settings should be favored for configuring |
551 | /// gesture behavior over the framework constants. |
552 | final DeviceGestureSettings gestureSettings; |
553 | |
554 | /// {@macro dart.ui.ViewConfiguration.displayFeatures} |
555 | /// |
556 | /// See also: |
557 | /// |
558 | /// * [dart:ui.DisplayFeatureType], which lists the different types of |
559 | /// display features and explains the differences between them. |
560 | /// * [dart:ui.DisplayFeatureState], which lists the possible states for |
561 | /// folding features ([dart:ui.DisplayFeatureType.fold] and |
562 | /// [dart:ui.DisplayFeatureType.hinge]). |
563 | final List<ui.DisplayFeature> displayFeatures; |
564 | |
565 | /// The orientation of the media (e.g., whether the device is in landscape or |
566 | /// portrait mode). |
567 | Orientation get orientation { |
568 | return size.width > size.height ? Orientation.landscape : Orientation.portrait; |
569 | } |
570 | |
571 | /// Creates a copy of this media query data but with the given fields replaced |
572 | /// with the new values. |
573 | /// |
574 | /// The `textScaler` parameter and `textScaleFactor` parameter must not be |
575 | /// both specified. |
576 | MediaQueryData copyWith({ |
577 | Size? size, |
578 | double? devicePixelRatio, |
579 | @Deprecated( |
580 | 'Use textScaler instead. ' |
581 | 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' |
582 | 'This feature was deprecated after v3.12.0-2.0.pre.' , |
583 | ) |
584 | double? textScaleFactor, |
585 | TextScaler? textScaler, |
586 | Brightness? platformBrightness, |
587 | EdgeInsets? padding, |
588 | EdgeInsets? viewPadding, |
589 | EdgeInsets? viewInsets, |
590 | EdgeInsets? systemGestureInsets, |
591 | bool? alwaysUse24HourFormat, |
592 | bool? highContrast, |
593 | bool? onOffSwitchLabels, |
594 | bool? disableAnimations, |
595 | bool? invertColors, |
596 | bool? accessibleNavigation, |
597 | bool? boldText, |
598 | NavigationMode? navigationMode, |
599 | DeviceGestureSettings? gestureSettings, |
600 | List<ui.DisplayFeature>? displayFeatures, |
601 | }) { |
602 | assert(textScaleFactor == null || textScaler == null); |
603 | if (textScaleFactor != null) { |
604 | textScaler ??= TextScaler.linear(textScaleFactor); |
605 | } |
606 | return MediaQueryData( |
607 | size: size ?? this.size, |
608 | devicePixelRatio: devicePixelRatio ?? this.devicePixelRatio, |
609 | textScaler: textScaler ?? this.textScaler, |
610 | platformBrightness: platformBrightness ?? this.platformBrightness, |
611 | padding: padding ?? this.padding, |
612 | viewPadding: viewPadding ?? this.viewPadding, |
613 | viewInsets: viewInsets ?? this.viewInsets, |
614 | systemGestureInsets: systemGestureInsets ?? this.systemGestureInsets, |
615 | alwaysUse24HourFormat: alwaysUse24HourFormat ?? this.alwaysUse24HourFormat, |
616 | invertColors: invertColors ?? this.invertColors, |
617 | highContrast: highContrast ?? this.highContrast, |
618 | onOffSwitchLabels: onOffSwitchLabels ?? this.onOffSwitchLabels, |
619 | disableAnimations: disableAnimations ?? this.disableAnimations, |
620 | accessibleNavigation: accessibleNavigation ?? this.accessibleNavigation, |
621 | boldText: boldText ?? this.boldText, |
622 | navigationMode: navigationMode ?? this.navigationMode, |
623 | gestureSettings: gestureSettings ?? this.gestureSettings, |
624 | displayFeatures: displayFeatures ?? this.displayFeatures, |
625 | ); |
626 | } |
627 | |
628 | /// Creates a copy of this media query data but with the given [padding]s |
629 | /// replaced with zero. |
630 | /// |
631 | /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and |
632 | /// `removeBottom` arguments are false (the default), then this |
633 | /// [MediaQueryData] is returned unmodified. |
634 | /// |
635 | /// See also: |
636 | /// |
637 | /// * [MediaQuery.removePadding], which uses this method to remove [padding] |
638 | /// from the ambient [MediaQuery]. |
639 | /// * [SafeArea], which both removes the padding from the [MediaQuery] and |
640 | /// adds a [Padding] widget. |
641 | /// * [removeViewInsets], the same thing but for [viewInsets]. |
642 | /// * [removeViewPadding], the same thing but for [viewPadding]. |
643 | MediaQueryData removePadding({ |
644 | bool removeLeft = false, |
645 | bool removeTop = false, |
646 | bool removeRight = false, |
647 | bool removeBottom = false, |
648 | }) { |
649 | if (!(removeLeft || removeTop || removeRight || removeBottom)) { |
650 | return this; |
651 | } |
652 | return copyWith( |
653 | padding: padding.copyWith( |
654 | left: removeLeft ? 0.0 : null, |
655 | top: removeTop ? 0.0 : null, |
656 | right: removeRight ? 0.0 : null, |
657 | bottom: removeBottom ? 0.0 : null, |
658 | ), |
659 | viewPadding: viewPadding.copyWith( |
660 | left: removeLeft ? math.max(0.0, viewPadding.left - padding.left) : null, |
661 | top: removeTop ? math.max(0.0, viewPadding.top - padding.top) : null, |
662 | right: removeRight ? math.max(0.0, viewPadding.right - padding.right) : null, |
663 | bottom: removeBottom ? math.max(0.0, viewPadding.bottom - padding.bottom) : null, |
664 | ), |
665 | ); |
666 | } |
667 | |
668 | /// Creates a copy of this media query data but with the given [viewInsets] |
669 | /// replaced with zero. |
670 | /// |
671 | /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and |
672 | /// `removeBottom` arguments are false (the default), then this |
673 | /// [MediaQueryData] is returned unmodified. |
674 | /// |
675 | /// See also: |
676 | /// |
677 | /// * [MediaQuery.removeViewInsets], which uses this method to remove |
678 | /// [viewInsets] from the ambient [MediaQuery]. |
679 | /// * [removePadding], the same thing but for [padding]. |
680 | /// * [removeViewPadding], the same thing but for [viewPadding]. |
681 | MediaQueryData removeViewInsets({ |
682 | bool removeLeft = false, |
683 | bool removeTop = false, |
684 | bool removeRight = false, |
685 | bool removeBottom = false, |
686 | }) { |
687 | if (!(removeLeft || removeTop || removeRight || removeBottom)) { |
688 | return this; |
689 | } |
690 | return copyWith( |
691 | viewPadding: viewPadding.copyWith( |
692 | left: removeLeft ? math.max(0.0, viewPadding.left - viewInsets.left) : null, |
693 | top: removeTop ? math.max(0.0, viewPadding.top - viewInsets.top) : null, |
694 | right: removeRight ? math.max(0.0, viewPadding.right - viewInsets.right) : null, |
695 | bottom: removeBottom ? math.max(0.0, viewPadding.bottom - viewInsets.bottom) : null, |
696 | ), |
697 | viewInsets: viewInsets.copyWith( |
698 | left: removeLeft ? 0.0 : null, |
699 | top: removeTop ? 0.0 : null, |
700 | right: removeRight ? 0.0 : null, |
701 | bottom: removeBottom ? 0.0 : null, |
702 | ), |
703 | ); |
704 | } |
705 | |
706 | /// Creates a copy of this media query data but with the given [viewPadding] |
707 | /// replaced with zero. |
708 | /// |
709 | /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and |
710 | /// `removeBottom` arguments are false (the default), then this |
711 | /// [MediaQueryData] is returned unmodified. |
712 | /// |
713 | /// See also: |
714 | /// |
715 | /// * [MediaQuery.removeViewPadding], which uses this method to remove |
716 | /// [viewPadding] from the ambient [MediaQuery]. |
717 | /// * [removePadding], the same thing but for [padding]. |
718 | /// * [removeViewInsets], the same thing but for [viewInsets]. |
719 | MediaQueryData removeViewPadding({ |
720 | bool removeLeft = false, |
721 | bool removeTop = false, |
722 | bool removeRight = false, |
723 | bool removeBottom = false, |
724 | }) { |
725 | if (!(removeLeft || removeTop || removeRight || removeBottom)) { |
726 | return this; |
727 | } |
728 | return copyWith( |
729 | padding: padding.copyWith( |
730 | left: removeLeft ? 0.0 : null, |
731 | top: removeTop ? 0.0 : null, |
732 | right: removeRight ? 0.0 : null, |
733 | bottom: removeBottom ? 0.0 : null, |
734 | ), |
735 | viewPadding: viewPadding.copyWith( |
736 | left: removeLeft ? 0.0 : null, |
737 | top: removeTop ? 0.0 : null, |
738 | right: removeRight ? 0.0 : null, |
739 | bottom: removeBottom ? 0.0 : null, |
740 | ), |
741 | ); |
742 | } |
743 | |
744 | /// Creates a copy of this media query data by removing [displayFeatures] that |
745 | /// are completely outside the given sub-screen and adjusting the [padding], |
746 | /// [viewInsets] and [viewPadding] to be zero on the sides that are not |
747 | /// included in the sub-screen. |
748 | /// |
749 | /// Returns unmodified [MediaQueryData] if the sub-screen coincides with the |
750 | /// available screen space. |
751 | /// |
752 | /// Asserts in debug mode, if the given sub-screen is outside the available |
753 | /// screen space. |
754 | /// |
755 | /// See also: |
756 | /// |
757 | /// * [DisplayFeatureSubScreen], which removes the display features that |
758 | /// split the screen, from the [MediaQuery] and adds a [Padding] widget to |
759 | /// position the child to match the selected sub-screen. |
760 | MediaQueryData removeDisplayFeatures(Rect subScreen) { |
761 | assert(subScreen.left >= 0.0 && subScreen.top >= 0.0 && |
762 | subScreen.right <= size.width && subScreen.bottom <= size.height, |
763 | "'subScreen' argument cannot be outside the bounds of the screen" ); |
764 | if (subScreen.size == size && subScreen.topLeft == Offset.zero) { |
765 | return this; |
766 | } |
767 | final double rightInset = size.width - subScreen.right; |
768 | final double bottomInset = size.height - subScreen.bottom; |
769 | return copyWith( |
770 | padding: EdgeInsets.only( |
771 | left: math.max(0.0, padding.left - subScreen.left), |
772 | top: math.max(0.0, padding.top - subScreen.top), |
773 | right: math.max(0.0, padding.right - rightInset), |
774 | bottom: math.max(0.0, padding.bottom - bottomInset), |
775 | ), |
776 | viewPadding: EdgeInsets.only( |
777 | left: math.max(0.0, viewPadding.left - subScreen.left), |
778 | top: math.max(0.0, viewPadding.top - subScreen.top), |
779 | right: math.max(0.0, viewPadding.right - rightInset), |
780 | bottom: math.max(0.0, viewPadding.bottom - bottomInset), |
781 | ), |
782 | viewInsets: EdgeInsets.only( |
783 | left: math.max(0.0, viewInsets.left - subScreen.left), |
784 | top: math.max(0.0, viewInsets.top - subScreen.top), |
785 | right: math.max(0.0, viewInsets.right - rightInset), |
786 | bottom: math.max(0.0, viewInsets.bottom - bottomInset), |
787 | ), |
788 | displayFeatures: displayFeatures.where( |
789 | (ui.DisplayFeature displayFeature) => subScreen.overlaps(displayFeature.bounds) |
790 | ).toList(), |
791 | ); |
792 | } |
793 | |
794 | @override |
795 | bool operator ==(Object other) { |
796 | if (other.runtimeType != runtimeType) { |
797 | return false; |
798 | } |
799 | return other is MediaQueryData |
800 | && other.size == size |
801 | && other.devicePixelRatio == devicePixelRatio |
802 | && other.textScaleFactor == textScaleFactor |
803 | && other.platformBrightness == platformBrightness |
804 | && other.padding == padding |
805 | && other.viewPadding == viewPadding |
806 | && other.viewInsets == viewInsets |
807 | && other.systemGestureInsets == systemGestureInsets |
808 | && other.alwaysUse24HourFormat == alwaysUse24HourFormat |
809 | && other.highContrast == highContrast |
810 | && other.onOffSwitchLabels == onOffSwitchLabels |
811 | && other.disableAnimations == disableAnimations |
812 | && other.invertColors == invertColors |
813 | && other.accessibleNavigation == accessibleNavigation |
814 | && other.boldText == boldText |
815 | && other.navigationMode == navigationMode |
816 | && other.gestureSettings == gestureSettings |
817 | && listEquals(other.displayFeatures, displayFeatures); |
818 | } |
819 | |
820 | @override |
821 | int get hashCode => Object.hash( |
822 | size, |
823 | devicePixelRatio, |
824 | textScaleFactor, |
825 | platformBrightness, |
826 | padding, |
827 | viewPadding, |
828 | viewInsets, |
829 | alwaysUse24HourFormat, |
830 | highContrast, |
831 | onOffSwitchLabels, |
832 | disableAnimations, |
833 | invertColors, |
834 | accessibleNavigation, |
835 | boldText, |
836 | navigationMode, |
837 | gestureSettings, |
838 | Object.hashAll(displayFeatures), |
839 | ); |
840 | |
841 | @override |
842 | String toString() { |
843 | final List<String> properties = <String>[ |
844 | 'size: $size' , |
845 | 'devicePixelRatio: ${devicePixelRatio.toStringAsFixed(1)}' , |
846 | 'textScaler: $textScaler' , |
847 | 'platformBrightness: $platformBrightness' , |
848 | 'padding: $padding' , |
849 | 'viewPadding: $viewPadding' , |
850 | 'viewInsets: $viewInsets' , |
851 | 'systemGestureInsets: $systemGestureInsets' , |
852 | 'alwaysUse24HourFormat: $alwaysUse24HourFormat' , |
853 | 'accessibleNavigation: $accessibleNavigation' , |
854 | 'highContrast: $highContrast' , |
855 | 'onOffSwitchLabels: $onOffSwitchLabels' , |
856 | 'disableAnimations: $disableAnimations' , |
857 | 'invertColors: $invertColors' , |
858 | 'boldText: $boldText' , |
859 | 'navigationMode: ${navigationMode.name}' , |
860 | 'gestureSettings: $gestureSettings' , |
861 | 'displayFeatures: $displayFeatures' , |
862 | ]; |
863 | return ' ${objectRuntimeType(this, 'MediaQueryData' )}( ${properties.join(', ' )})' ; |
864 | } |
865 | } |
866 | |
867 | /// Establishes a subtree in which media queries resolve to the given data. |
868 | /// |
869 | /// For example, to learn the size of the current view (e.g., |
870 | /// the [FlutterView] containing your app), you can use [MediaQuery.sizeOf]: |
871 | /// `MediaQuery.sizeOf(context)`. |
872 | /// |
873 | /// Querying the current media using specific methods (for example, |
874 | /// [MediaQuery.sizeOf] or [MediaQuery.paddingOf]) will cause your widget to |
875 | /// rebuild automatically whenever that specific property changes. |
876 | /// |
877 | /// {@template flutter.widgets.media_query.MediaQuery.useSpecific} |
878 | /// Querying using [MediaQuery.of] will cause your widget to rebuild |
879 | /// automatically whenever _any_ field of the [MediaQueryData] changes (e.g., if |
880 | /// the user rotates their device). Therefore, unless you are concerned with the |
881 | /// entire [MediaQueryData] object changing, prefer using the specific methods |
882 | /// (for example: [MediaQuery.sizeOf] and [MediaQuery.paddingOf]), as it will |
883 | /// rebuild more efficiently. |
884 | /// |
885 | /// If no [MediaQuery] is in scope then [MediaQuery.of] and the "...Of" methods |
886 | /// similar to [MediaQuery.sizeOf] will throw an exception. Alternatively, the |
887 | /// "maybe-" variant methods (such as [MediaQuery.maybeOf] and |
888 | /// [MediaQuery.maybeSizeOf]) can be used, which return null, instead of |
889 | /// throwing, when no [MediaQuery] is in scope. |
890 | /// {@endtemplate} |
891 | /// |
892 | /// {@youtube 560 315 https://www.youtube.com/watch?v=A3WrA4zAaPw} |
893 | /// |
894 | /// See also: |
895 | /// |
896 | /// * [WidgetsApp] and [MaterialApp], which introduce a [MediaQuery] and keep |
897 | /// it up to date with the current screen metrics as they change. |
898 | /// * [MediaQueryData], the data structure that represents the metrics. |
899 | class MediaQuery extends InheritedModel<_MediaQueryAspect> { |
900 | /// Creates a widget that provides [MediaQueryData] to its descendants. |
901 | const MediaQuery({ |
902 | super.key, |
903 | required this.data, |
904 | required super.child, |
905 | }); |
906 | |
907 | /// Creates a new [MediaQuery] that inherits from the ambient [MediaQuery] |
908 | /// from the given context, but removes the specified padding. |
909 | /// |
910 | /// This should be inserted into the widget tree when the [MediaQuery] padding |
911 | /// is consumed by a widget in such a way that the padding is no longer |
912 | /// exposed to the widget's descendants or siblings. |
913 | /// |
914 | /// The [context] argument must have a [MediaQuery] in scope. |
915 | /// |
916 | /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and |
917 | /// `removeBottom` arguments are false (the default), then the returned |
918 | /// [MediaQuery] reuses the ambient [MediaQueryData] unmodified, which is not |
919 | /// particularly useful. |
920 | /// |
921 | /// See also: |
922 | /// |
923 | /// * [SafeArea], which both removes the padding from the [MediaQuery] and |
924 | /// adds a [Padding] widget. |
925 | /// * [MediaQueryData.padding], the affected property of the |
926 | /// [MediaQueryData]. |
927 | /// * [removeViewInsets], the same thing but for [MediaQueryData.viewInsets]. |
928 | /// * [removeViewPadding], the same thing but for |
929 | /// [MediaQueryData.viewPadding]. |
930 | factory MediaQuery.removePadding({ |
931 | Key? key, |
932 | required BuildContext context, |
933 | bool removeLeft = false, |
934 | bool removeTop = false, |
935 | bool removeRight = false, |
936 | bool removeBottom = false, |
937 | required Widget child, |
938 | }) { |
939 | return MediaQuery( |
940 | key: key, |
941 | data: MediaQuery.of(context).removePadding( |
942 | removeLeft: removeLeft, |
943 | removeTop: removeTop, |
944 | removeRight: removeRight, |
945 | removeBottom: removeBottom, |
946 | ), |
947 | child: child, |
948 | ); |
949 | } |
950 | |
951 | /// Creates a new [MediaQuery] that inherits from the ambient [MediaQuery] |
952 | /// from the given context, but removes the specified view insets. |
953 | /// |
954 | /// This should be inserted into the widget tree when the [MediaQuery] view |
955 | /// insets are consumed by a widget in such a way that the view insets are no |
956 | /// longer exposed to the widget's descendants or siblings. |
957 | /// |
958 | /// The [context] argument must have a [MediaQuery] in scope. |
959 | /// |
960 | /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and |
961 | /// `removeBottom` arguments are false (the default), then the returned |
962 | /// [MediaQuery] reuses the ambient [MediaQueryData] unmodified, which is not |
963 | /// particularly useful. |
964 | /// |
965 | /// See also: |
966 | /// |
967 | /// * [MediaQueryData.viewInsets], the affected property of the |
968 | /// [MediaQueryData]. |
969 | /// * [removePadding], the same thing but for [MediaQueryData.padding]. |
970 | /// * [removeViewPadding], the same thing but for |
971 | /// [MediaQueryData.viewPadding]. |
972 | factory MediaQuery.removeViewInsets({ |
973 | Key? key, |
974 | required BuildContext context, |
975 | bool removeLeft = false, |
976 | bool removeTop = false, |
977 | bool removeRight = false, |
978 | bool removeBottom = false, |
979 | required Widget child, |
980 | }) { |
981 | return MediaQuery( |
982 | key: key, |
983 | data: MediaQuery.of(context).removeViewInsets( |
984 | removeLeft: removeLeft, |
985 | removeTop: removeTop, |
986 | removeRight: removeRight, |
987 | removeBottom: removeBottom, |
988 | ), |
989 | child: child, |
990 | ); |
991 | } |
992 | |
993 | /// Creates a new [MediaQuery] that inherits from the ambient [MediaQuery] |
994 | /// from the given context, but removes the specified view padding. |
995 | /// |
996 | /// This should be inserted into the widget tree when the [MediaQuery] view |
997 | /// padding is consumed by a widget in such a way that the view padding is no |
998 | /// longer exposed to the widget's descendants or siblings. |
999 | /// |
1000 | /// The [context] argument must have a [MediaQuery] in scope. |
1001 | /// |
1002 | /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and |
1003 | /// `removeBottom` arguments are false (the default), then the returned |
1004 | /// [MediaQuery] reuses the ambient [MediaQueryData] unmodified, which is not |
1005 | /// particularly useful. |
1006 | /// |
1007 | /// See also: |
1008 | /// |
1009 | /// * [MediaQueryData.viewPadding], the affected property of the |
1010 | /// [MediaQueryData]. |
1011 | /// * [removePadding], the same thing but for [MediaQueryData.padding]. |
1012 | /// * [removeViewInsets], the same thing but for [MediaQueryData.viewInsets]. |
1013 | factory MediaQuery.removeViewPadding({ |
1014 | Key? key, |
1015 | required BuildContext context, |
1016 | bool removeLeft = false, |
1017 | bool removeTop = false, |
1018 | bool removeRight = false, |
1019 | bool removeBottom = false, |
1020 | required Widget child, |
1021 | }) { |
1022 | return MediaQuery( |
1023 | key: key, |
1024 | data: MediaQuery.of(context).removeViewPadding( |
1025 | removeLeft: removeLeft, |
1026 | removeTop: removeTop, |
1027 | removeRight: removeRight, |
1028 | removeBottom: removeBottom, |
1029 | ), |
1030 | child: child, |
1031 | ); |
1032 | } |
1033 | |
1034 | /// Deprecated. Use [MediaQuery.fromView] instead. |
1035 | /// |
1036 | /// This constructor was operating on a single window assumption. In |
1037 | /// preparation for Flutter's upcoming multi-window support, it has been |
1038 | /// deprecated. |
1039 | /// |
1040 | /// Replaced by [MediaQuery.fromView], which requires specifying the |
1041 | /// [FlutterView] the [MediaQuery] is constructed for. The [FlutterView] can, |
1042 | /// for example, be obtained from the context via [View.of] or from |
1043 | /// [PlatformDispatcher.views]. |
1044 | @Deprecated( |
1045 | 'Use MediaQuery.fromView instead. ' |
1046 | 'This constructor was deprecated in preparation for the upcoming multi-window support. ' |
1047 | 'This feature was deprecated after v3.7.0-32.0.pre.' |
1048 | ) |
1049 | static Widget fromWindow({ |
1050 | Key? key, |
1051 | required Widget child, |
1052 | }) { |
1053 | return _MediaQueryFromView( |
1054 | key: key, |
1055 | view: WidgetsBinding.instance.window, |
1056 | ignoreParentData: true, |
1057 | child: child, |
1058 | ); |
1059 | } |
1060 | |
1061 | /// Wraps the [child] in a [MediaQuery] which is built using data from the |
1062 | /// provided [view]. |
1063 | /// |
1064 | /// The [MediaQuery] is constructed using the platform-specific data of the |
1065 | /// surrounding [MediaQuery] and the view-specific data of the provided |
1066 | /// [view]. If no surrounding [MediaQuery] exists, the platform-specific data |
1067 | /// is generated from the [PlatformDispatcher] associated with the provided |
1068 | /// [view]. Any information that's exposed via the [PlatformDispatcher] is |
1069 | /// considered platform-specific. Data exposed directly on the [FlutterView] |
1070 | /// (excluding its [FlutterView.platformDispatcher] property) is considered |
1071 | /// view-specific. |
1072 | /// |
1073 | /// The injected [MediaQuery] automatically updates when any of the data used |
1074 | /// to construct it changes. |
1075 | static Widget fromView({ |
1076 | Key? key, |
1077 | required FlutterView view, |
1078 | required Widget child, |
1079 | }) { |
1080 | return _MediaQueryFromView( |
1081 | key: key, |
1082 | view: view, |
1083 | child: child, |
1084 | ); |
1085 | } |
1086 | |
1087 | /// Wraps the `child` in a [MediaQuery] with its [MediaQueryData.textScaler] |
1088 | /// set to [TextScaler.noScaling]. |
1089 | /// |
1090 | /// The returned widget must be inserted in a widget tree below an existing |
1091 | /// [MediaQuery] widget. |
1092 | /// |
1093 | /// This can be used to prevent, for example, icon fonts from scaling as the |
1094 | /// user adjusts the platform's text scaling value. |
1095 | static Widget withNoTextScaling({ |
1096 | Key? key, |
1097 | required Widget child, |
1098 | }) { |
1099 | return Builder( |
1100 | key: key, |
1101 | builder: (BuildContext context) { |
1102 | assert(debugCheckHasMediaQuery(context)); |
1103 | return MediaQuery( |
1104 | data: MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling), |
1105 | child: child, |
1106 | ); |
1107 | }, |
1108 | ); |
1109 | } |
1110 | |
1111 | /// Wraps the `child` in a [MediaQuery] and applies [TextScaler.clamp] on the |
1112 | /// current [MediaQueryData.textScaler]. |
1113 | /// |
1114 | /// The returned widget must be inserted in a widget tree below an existing |
1115 | /// [MediaQuery] widget. |
1116 | /// |
1117 | /// This is a convenience function to restrict the range of the scaled text |
1118 | /// size to `[minScaleFactor * fontSize, maxScaleFactor * fontSize]` (to |
1119 | /// prevent excessive text scaling that would break the UI, for example). When |
1120 | /// `minScaleFactor` equals `maxScaleFactor`, the scaler becomes |
1121 | /// `TextScaler.linear(minScaleFactor)`. |
1122 | static Widget withClampedTextScaling({ |
1123 | Key? key, |
1124 | double minScaleFactor = 0.0, |
1125 | double maxScaleFactor = double.infinity, |
1126 | required Widget child, |
1127 | }) { |
1128 | assert(maxScaleFactor >= minScaleFactor); |
1129 | assert(!maxScaleFactor.isNaN); |
1130 | assert(minScaleFactor.isFinite); |
1131 | assert(minScaleFactor >= 0); |
1132 | |
1133 | return Builder(builder: (BuildContext context) { |
1134 | assert(debugCheckHasMediaQuery(context)); |
1135 | final MediaQueryData data = MediaQuery.of(context); |
1136 | return MediaQuery( |
1137 | data: data.copyWith( |
1138 | textScaler: data.textScaler.clamp(minScaleFactor: minScaleFactor, maxScaleFactor: maxScaleFactor), |
1139 | ), |
1140 | child: child, |
1141 | ); |
1142 | }); |
1143 | } |
1144 | |
1145 | /// Contains information about the current media. |
1146 | /// |
1147 | /// For example, the [MediaQueryData.size] property contains the width and |
1148 | /// height of the current window. |
1149 | final MediaQueryData data; |
1150 | |
1151 | /// The data from the closest instance of this class that encloses the given |
1152 | /// context. |
1153 | /// |
1154 | /// You can use this function to query the entire set of data held in the |
1155 | /// current [MediaQueryData] object. When any of that information changes, |
1156 | /// your widget will be scheduled to be rebuilt, keeping your widget |
1157 | /// up-to-date. |
1158 | /// |
1159 | /// Since it is typical that the widget only requires a subset of properties |
1160 | /// of the [MediaQueryData] object, prefer using the more specific methods |
1161 | /// (for example: [MediaQuery.sizeOf] and [MediaQuery.paddingOf]), as those |
1162 | /// methods will not cause a widget to rebuild when unrelated properties are |
1163 | /// updated. |
1164 | /// |
1165 | /// Typical usage is as follows: |
1166 | /// |
1167 | /// ```dart |
1168 | /// MediaQueryData media = MediaQuery.of(context); |
1169 | /// ``` |
1170 | /// |
1171 | /// If there is no [MediaQuery] in scope, this method will throw a [TypeError] |
1172 | /// exception in release builds, and throw a descriptive [FlutterError] in |
1173 | /// debug builds. |
1174 | /// |
1175 | /// See also: |
1176 | /// |
1177 | /// * [maybeOf], which doesn't throw or assert if it doesn't find a |
1178 | /// [MediaQuery] ancestor. It returns null instead. |
1179 | /// * [sizeOf] and other specific methods for retrieving and depending on |
1180 | /// changes of a specific value. |
1181 | static MediaQueryData of(BuildContext context) { |
1182 | return _of(context); |
1183 | } |
1184 | |
1185 | static MediaQueryData _of(BuildContext context, [_MediaQueryAspect? aspect]) { |
1186 | assert(debugCheckHasMediaQuery(context)); |
1187 | return InheritedModel.inheritFrom<MediaQuery>(context, aspect: aspect)!.data; |
1188 | } |
1189 | |
1190 | /// The data from the closest instance of this class that encloses the given |
1191 | /// context, if any. |
1192 | /// |
1193 | /// Use this function if you want to allow situations where no [MediaQuery] is |
1194 | /// in scope. Prefer using [MediaQuery.of] in situations where a media query |
1195 | /// is always expected to exist. |
1196 | /// |
1197 | /// If there is no [MediaQuery] in scope, then this function will return null. |
1198 | /// |
1199 | /// You can use this function to query the entire set of data held in the |
1200 | /// current [MediaQueryData] object. When any of that information changes, |
1201 | /// your widget will be scheduled to be rebuilt, keeping your widget |
1202 | /// up-to-date. |
1203 | /// |
1204 | /// Since it is typical that the widget only requires a subset of properties |
1205 | /// of the [MediaQueryData] object, prefer using the more specific methods |
1206 | /// (for example: [MediaQuery.maybeSizeOf] and [MediaQuery.maybePaddingOf]), |
1207 | /// as those methods will not cause a widget to rebuild when unrelated |
1208 | /// properties are updated. |
1209 | /// |
1210 | /// Typical usage is as follows: |
1211 | /// |
1212 | /// ```dart |
1213 | /// MediaQueryData? mediaQuery = MediaQuery.maybeOf(context); |
1214 | /// if (mediaQuery == null) { |
1215 | /// // Do something else instead. |
1216 | /// } |
1217 | /// ``` |
1218 | /// |
1219 | /// See also: |
1220 | /// |
1221 | /// * [of], which will throw if it doesn't find a [MediaQuery] ancestor, |
1222 | /// instead of returning null. |
1223 | /// * [maybeSizeOf] and other specific methods for retrieving and depending on |
1224 | /// changes of a specific value. |
1225 | static MediaQueryData? maybeOf(BuildContext context) { |
1226 | return _maybeOf(context); |
1227 | } |
1228 | |
1229 | static MediaQueryData? _maybeOf(BuildContext context, [_MediaQueryAspect? aspect]) { |
1230 | return InheritedModel.inheritFrom<MediaQuery>(context, aspect: aspect)?.data; |
1231 | } |
1232 | |
1233 | /// Returns [MediaQueryData.size] from the nearest [MediaQuery] ancestor or |
1234 | /// throws an exception, if no such ancestor exists. |
1235 | /// |
1236 | /// Use of this method will cause the given [context] to rebuild any time that |
1237 | /// the [MediaQueryData.size] property of the ancestor [MediaQuery] changes. |
1238 | /// |
1239 | /// {@template flutter.widgets.media_query.MediaQuery.dontUseOf} |
1240 | /// Prefer using this function over getting the attribute directly from the |
1241 | /// [MediaQueryData] returned from [of], because using this function will only |
1242 | /// rebuild the `context` when this specific attribute changes, not when _any_ |
1243 | /// attribute changes. |
1244 | /// {@endtemplate} |
1245 | static Size sizeOf(BuildContext context) => _of(context, _MediaQueryAspect.size).size; |
1246 | |
1247 | /// Returns [MediaQueryData.size] from the nearest [MediaQuery] ancestor or |
1248 | /// null, if no such ancestor exists. |
1249 | /// |
1250 | /// Use of this method will cause the given [context] to rebuild any time that |
1251 | /// the [MediaQueryData.size] property of the ancestor [MediaQuery] changes. |
1252 | /// |
1253 | /// {@template flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1254 | /// Prefer using this function over getting the attribute directly from the |
1255 | /// [MediaQueryData] returned from [maybeOf], because using this function will |
1256 | /// only rebuild the `context` when this specific attribute changes, not when |
1257 | /// _any_ attribute changes. |
1258 | /// {@endtemplate} |
1259 | static Size? maybeSizeOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.size)?.size; |
1260 | |
1261 | /// Returns [MediaQueryData.orientation] for the nearest [MediaQuery] ancestor or |
1262 | /// throws an exception, if no such ancestor exists. |
1263 | /// |
1264 | /// Use of this method will cause the given [context] to rebuild any time that |
1265 | /// the [MediaQueryData.orientation] property of the ancestor [MediaQuery] changes. |
1266 | /// |
1267 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1268 | static Orientation orientationOf(BuildContext context) => _of(context, _MediaQueryAspect.orientation).orientation; |
1269 | |
1270 | /// Returns [MediaQueryData.orientation] for the nearest [MediaQuery] ancestor or |
1271 | /// null, if no such ancestor exists. |
1272 | /// |
1273 | /// Use of this method will cause the given [context] to rebuild any time that |
1274 | /// the [MediaQueryData.orientation] property of the ancestor [MediaQuery] changes. |
1275 | /// |
1276 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1277 | static Orientation? maybeOrientationOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.orientation)?.orientation; |
1278 | |
1279 | /// Returns [MediaQueryData.devicePixelRatio] for the nearest [MediaQuery] ancestor or |
1280 | /// throws an exception, if no such ancestor exists. |
1281 | /// |
1282 | /// Use of this method will cause the given [context] to rebuild any time that |
1283 | /// the [MediaQueryData.devicePixelRatio] property of the ancestor [MediaQuery] changes. |
1284 | /// |
1285 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1286 | static double devicePixelRatioOf(BuildContext context) => _of(context, _MediaQueryAspect.devicePixelRatio).devicePixelRatio; |
1287 | |
1288 | /// Returns [MediaQueryData.devicePixelRatio] for the nearest [MediaQuery] ancestor or |
1289 | /// null, if no such ancestor exists. |
1290 | /// |
1291 | /// Use of this method will cause the given [context] to rebuild any time that |
1292 | /// the [MediaQueryData.devicePixelRatio] property of the ancestor [MediaQuery] changes. |
1293 | /// |
1294 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1295 | static double? maybeDevicePixelRatioOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.devicePixelRatio)?.devicePixelRatio; |
1296 | |
1297 | /// Deprecated. Will be removed in a future version of Flutter. Use |
1298 | /// [maybeTextScalerOf] instead. |
1299 | /// |
1300 | /// Returns [MediaQueryData.textScaleFactor] for the nearest [MediaQuery] ancestor or |
1301 | /// 1.0, if no such ancestor exists. |
1302 | /// |
1303 | /// Use of this method will cause the given [context] to rebuild any time that |
1304 | /// the [MediaQueryData.textScaleFactor] property of the ancestor [MediaQuery] changes. |
1305 | /// |
1306 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1307 | @Deprecated( |
1308 | 'Use textScalerOf instead. ' |
1309 | 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' |
1310 | 'This feature was deprecated after v3.12.0-2.0.pre.' , |
1311 | ) |
1312 | static double textScaleFactorOf(BuildContext context) => maybeTextScaleFactorOf(context) ?? 1.0; |
1313 | |
1314 | /// Deprecated. Will be removed in a future version of Flutter. Use |
1315 | /// [maybeTextScalerOf] instead. |
1316 | /// |
1317 | /// Returns [MediaQueryData.textScaleFactor] for the nearest [MediaQuery] ancestor or |
1318 | /// null, if no such ancestor exists. |
1319 | /// |
1320 | /// Use of this method will cause the given [context] to rebuild any time that |
1321 | /// the [MediaQueryData.textScaleFactor] property of the ancestor [MediaQuery] |
1322 | /// changes. |
1323 | /// |
1324 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1325 | @Deprecated( |
1326 | 'Use maybeTextScalerOf instead. ' |
1327 | 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' |
1328 | 'This feature was deprecated after v3.12.0-2.0.pre.' , |
1329 | ) |
1330 | static double? maybeTextScaleFactorOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.textScaleFactor)?.textScaleFactor; |
1331 | |
1332 | /// Returns the [MediaQueryData.textScaler] for the nearest [MediaQuery] |
1333 | /// ancestor or [TextScaler.noScaling] if no such ancestor exists. |
1334 | /// |
1335 | /// Use of this method will cause the given [context] to rebuild any time that |
1336 | /// the [MediaQueryData.textScaler] property of the ancestor [MediaQuery] |
1337 | /// changes. |
1338 | /// |
1339 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1340 | static TextScaler textScalerOf(BuildContext context) => maybeTextScalerOf(context) ?? TextScaler.noScaling; |
1341 | |
1342 | /// Returns the [MediaQueryData.textScaler] for the nearest [MediaQuery] |
1343 | /// ancestor or null if no such ancestor exists. |
1344 | /// |
1345 | /// Use of this method will cause the given [context] to rebuild any time that |
1346 | /// the [MediaQueryData.textScaler] property of the ancestor [MediaQuery] |
1347 | /// changes. |
1348 | /// |
1349 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1350 | static TextScaler? maybeTextScalerOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.textScaler)?.textScaler; |
1351 | |
1352 | /// Returns [MediaQueryData.platformBrightness] for the nearest [MediaQuery] |
1353 | /// ancestor or [Brightness.light], if no such ancestor exists. |
1354 | /// |
1355 | /// Use of this method will cause the given [context] to rebuild any time that |
1356 | /// the [MediaQueryData.platformBrightness] property of the ancestor |
1357 | /// [MediaQuery] changes. |
1358 | /// |
1359 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1360 | static Brightness platformBrightnessOf(BuildContext context) => maybePlatformBrightnessOf(context) ?? Brightness.light; |
1361 | |
1362 | /// Returns [MediaQueryData.platformBrightness] for the nearest [MediaQuery] |
1363 | /// ancestor or null, if no such ancestor exists. |
1364 | /// |
1365 | /// Use of this method will cause the given [context] to rebuild any time that |
1366 | /// the [MediaQueryData.platformBrightness] property of the ancestor |
1367 | /// [MediaQuery] changes. |
1368 | /// |
1369 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1370 | static Brightness? maybePlatformBrightnessOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.platformBrightness)?.platformBrightness; |
1371 | |
1372 | /// Returns [MediaQueryData.padding] for the nearest [MediaQuery] ancestor or |
1373 | /// throws an exception, if no such ancestor exists. |
1374 | /// |
1375 | /// Use of this method will cause the given [context] to rebuild any time that |
1376 | /// the [MediaQueryData.padding] property of the ancestor [MediaQuery] |
1377 | /// changes. |
1378 | /// |
1379 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1380 | static EdgeInsets paddingOf(BuildContext context) => _of(context, _MediaQueryAspect.padding).padding; |
1381 | |
1382 | /// Returns [MediaQueryData.padding] for the nearest [MediaQuery] ancestor |
1383 | /// or null, if no such ancestor exists. |
1384 | /// |
1385 | /// Use of this method will cause the given [context] to rebuild any time that |
1386 | /// the [MediaQueryData.padding] property of the ancestor [MediaQuery] |
1387 | /// changes. |
1388 | /// |
1389 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1390 | static EdgeInsets? maybePaddingOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.padding)?.padding; |
1391 | |
1392 | /// Returns [MediaQueryData.viewInsets] for the nearest [MediaQuery] ancestor |
1393 | /// or throws an exception, if no such ancestor exists. |
1394 | /// |
1395 | /// Use of this method will cause the given [context] to rebuild any time that |
1396 | /// the [MediaQueryData.viewInsets] property of the ancestor [MediaQuery] |
1397 | /// changes. |
1398 | /// |
1399 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1400 | static EdgeInsets viewInsetsOf(BuildContext context) => _of(context, _MediaQueryAspect.viewInsets).viewInsets; |
1401 | |
1402 | /// Returns [MediaQueryData.viewInsets] for the nearest [MediaQuery] ancestor |
1403 | /// or null, if no such ancestor exists. |
1404 | /// |
1405 | /// Use of this method will cause the given [context] to rebuild any time that |
1406 | /// the [MediaQueryData.viewInsets] property of the ancestor [MediaQuery] |
1407 | /// changes. |
1408 | /// |
1409 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1410 | static EdgeInsets? maybeViewInsetsOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.viewInsets)?.viewInsets; |
1411 | |
1412 | /// Returns [MediaQueryData.systemGestureInsets] for the nearest [MediaQuery] |
1413 | /// ancestor or throws an exception, if no such ancestor exists. |
1414 | /// |
1415 | /// Use of this method will cause the given [context] to rebuild any time that |
1416 | /// the [MediaQueryData.systemGestureInsets] property of the ancestor |
1417 | /// [MediaQuery] changes. |
1418 | /// |
1419 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1420 | static EdgeInsets systemGestureInsetsOf(BuildContext context) => _of(context, _MediaQueryAspect.systemGestureInsets).systemGestureInsets; |
1421 | |
1422 | /// Returns [MediaQueryData.systemGestureInsets] for the nearest [MediaQuery] |
1423 | /// ancestor or null, if no such ancestor exists. |
1424 | /// |
1425 | /// Use of this method will cause the given [context] to rebuild any time that |
1426 | /// the [MediaQueryData.systemGestureInsets] property of the ancestor |
1427 | /// [MediaQuery] changes. |
1428 | /// |
1429 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1430 | static EdgeInsets? maybeSystemGestureInsetsOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.systemGestureInsets)?.systemGestureInsets; |
1431 | |
1432 | /// Returns [MediaQueryData.viewPadding] for the nearest [MediaQuery] ancestor |
1433 | /// or throws an exception, if no such ancestor exists. |
1434 | /// |
1435 | /// Use of this method will cause the given [context] to rebuild any time that |
1436 | /// the [MediaQueryData.viewPadding] property of the ancestor [MediaQuery] |
1437 | /// changes. |
1438 | /// |
1439 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1440 | static EdgeInsets viewPaddingOf(BuildContext context) => _of(context, _MediaQueryAspect.viewPadding).viewPadding; |
1441 | |
1442 | /// Returns [MediaQueryData.viewPadding] for the nearest [MediaQuery] ancestor |
1443 | /// or null, if no such ancestor exists. |
1444 | /// |
1445 | /// Use of this method will cause the given [context] to rebuild any time that |
1446 | /// the [MediaQueryData.viewPadding] property of the ancestor [MediaQuery] |
1447 | /// changes. |
1448 | /// |
1449 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1450 | static EdgeInsets? maybeViewPaddingOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.viewPadding)?.viewPadding; |
1451 | |
1452 | /// Returns [MediaQueryData.alwaysUse24HourFormat] for the nearest |
1453 | /// [MediaQuery] ancestor or throws an exception, if no such ancestor exists. |
1454 | /// |
1455 | /// Use of this method will cause the given [context] to rebuild any time that |
1456 | /// the [MediaQueryData.alwaysUse24HourFormat] property of the ancestor |
1457 | /// [MediaQuery] changes. |
1458 | /// |
1459 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1460 | static bool alwaysUse24HourFormatOf(BuildContext context) => _of(context, _MediaQueryAspect.alwaysUse24HourFormat).alwaysUse24HourFormat; |
1461 | |
1462 | /// Returns [MediaQueryData.alwaysUse24HourFormat] for the nearest |
1463 | /// [MediaQuery] ancestor or null, if no such ancestor exists. |
1464 | /// |
1465 | /// Use of this method will cause the given [context] to rebuild any time that |
1466 | /// the [MediaQueryData.alwaysUse24HourFormat] property of the ancestor |
1467 | /// [MediaQuery] changes. |
1468 | /// |
1469 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1470 | static bool? maybeAlwaysUse24HourFormatOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.alwaysUse24HourFormat)?.alwaysUse24HourFormat; |
1471 | |
1472 | /// Returns [MediaQueryData.accessibleNavigation] for the nearest [MediaQuery] |
1473 | /// ancestor or throws an exception, if no such ancestor exists. |
1474 | /// |
1475 | /// Use of this method will cause the given [context] to rebuild any time that |
1476 | /// the [MediaQueryData.accessibleNavigation] property of the ancestor |
1477 | /// [MediaQuery] changes. |
1478 | /// |
1479 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1480 | static bool accessibleNavigationOf(BuildContext context) => _of(context, _MediaQueryAspect.accessibleNavigation).accessibleNavigation; |
1481 | |
1482 | /// Returns [MediaQueryData.accessibleNavigation] for the nearest [MediaQuery] |
1483 | /// ancestor or null, if no such ancestor exists. |
1484 | /// |
1485 | /// Use of this method will cause the given [context] to rebuild any time that |
1486 | /// the [MediaQueryData.accessibleNavigation] property of the ancestor |
1487 | /// [MediaQuery] changes. |
1488 | /// |
1489 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1490 | static bool? maybeAccessibleNavigationOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.accessibleNavigation)?.accessibleNavigation; |
1491 | |
1492 | /// Returns [MediaQueryData.invertColors] for the nearest [MediaQuery] |
1493 | /// ancestor or throws an exception, if no such ancestor exists. |
1494 | /// |
1495 | /// Use of this method will cause the given [context] to rebuild any time that |
1496 | /// the [MediaQueryData.invertColors] property of the ancestor [MediaQuery] |
1497 | /// changes. |
1498 | /// |
1499 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1500 | static bool invertColorsOf(BuildContext context) => _of(context, _MediaQueryAspect.invertColors).invertColors; |
1501 | |
1502 | /// Returns [MediaQueryData.invertColors] for the nearest [MediaQuery] |
1503 | /// ancestor or null, if no such ancestor exists. |
1504 | /// |
1505 | /// Use of this method will cause the given [context] to rebuild any time that |
1506 | /// the [MediaQueryData.invertColors] property of the ancestor [MediaQuery] |
1507 | /// changes. |
1508 | /// |
1509 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1510 | static bool? maybeInvertColorsOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.invertColors)?.invertColors; |
1511 | |
1512 | /// Returns [MediaQueryData.highContrast] for the nearest [MediaQuery] |
1513 | /// ancestor or false, if no such ancestor exists. |
1514 | /// |
1515 | /// Use of this method will cause the given [context] to rebuild any time that |
1516 | /// the [MediaQueryData.highContrast] property of the ancestor [MediaQuery] |
1517 | /// changes. |
1518 | /// |
1519 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1520 | static bool highContrastOf(BuildContext context) => maybeHighContrastOf(context) ?? false; |
1521 | |
1522 | /// Returns [MediaQueryData.highContrast] for the nearest [MediaQuery] |
1523 | /// ancestor or null, if no such ancestor exists. |
1524 | /// |
1525 | /// Use of this method will cause the given [context] to rebuild any time that |
1526 | /// the [MediaQueryData.highContrast] property of the ancestor [MediaQuery] |
1527 | /// changes. |
1528 | /// |
1529 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1530 | static bool? maybeHighContrastOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.highContrast)?.highContrast; |
1531 | |
1532 | /// Returns [MediaQueryData.onOffSwitchLabels] for the nearest [MediaQuery] |
1533 | /// ancestor or false, if no such ancestor exists. |
1534 | /// |
1535 | /// Use of this method will cause the given [context] to rebuild any time that |
1536 | /// the [MediaQueryData.onOffSwitchLabels] property of the ancestor |
1537 | /// [MediaQuery] changes. |
1538 | /// |
1539 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1540 | static bool onOffSwitchLabelsOf(BuildContext context) => maybeOnOffSwitchLabelsOf(context) ?? false; |
1541 | |
1542 | /// Returns [MediaQueryData.onOffSwitchLabels] for the nearest [MediaQuery] |
1543 | /// ancestor or null, if no such ancestor exists. |
1544 | /// |
1545 | /// Use of this method will cause the given [context] to rebuild any time that |
1546 | /// the [MediaQueryData.onOffSwitchLabels] property of the ancestor |
1547 | /// [MediaQuery] changes. |
1548 | /// |
1549 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1550 | static bool? maybeOnOffSwitchLabelsOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.onOffSwitchLabels)?.onOffSwitchLabels; |
1551 | |
1552 | /// Returns [MediaQueryData.disableAnimations] for the nearest [MediaQuery] |
1553 | /// ancestor or false, if no such ancestor exists. |
1554 | /// |
1555 | /// Use of this method will cause the given [context] to rebuild any time that |
1556 | /// the [MediaQueryData.disableAnimations] property of the ancestor |
1557 | /// [MediaQuery] changes. |
1558 | /// |
1559 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1560 | static bool disableAnimationsOf(BuildContext context) => _of(context, _MediaQueryAspect.disableAnimations).disableAnimations; |
1561 | |
1562 | /// Returns [MediaQueryData.disableAnimations] for the nearest [MediaQuery] |
1563 | /// ancestor or null, if no such ancestor exists. |
1564 | /// |
1565 | /// Use of this method will cause the given [context] to rebuild any time that |
1566 | /// the [MediaQueryData.disableAnimations] property of the ancestor |
1567 | /// [MediaQuery] changes. |
1568 | /// |
1569 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1570 | static bool? maybeDisableAnimationsOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.disableAnimations)?.disableAnimations; |
1571 | |
1572 | /// Returns the [MediaQueryData.boldText] accessibility setting for the |
1573 | /// nearest [MediaQuery] ancestor or false, if no such ancestor exists. |
1574 | /// |
1575 | /// Use of this method will cause the given [context] to rebuild any time that |
1576 | /// the [MediaQueryData.boldText] property of the ancestor [MediaQuery] |
1577 | /// changes. |
1578 | /// |
1579 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1580 | static bool boldTextOf(BuildContext context) => maybeBoldTextOf(context) ?? false; |
1581 | |
1582 | /// Returns the [MediaQueryData.boldText] accessibility setting for the |
1583 | /// nearest [MediaQuery] ancestor or false, if no such ancestor exists. |
1584 | /// |
1585 | /// Use of this method will cause the given [context] to rebuild any time that |
1586 | /// the [MediaQueryData.boldText] property of the ancestor [MediaQuery] |
1587 | /// changes. |
1588 | /// |
1589 | /// Deprecated in favor of [boldTextOf]. |
1590 | @Deprecated( |
1591 | 'Migrate to boldTextOf. ' |
1592 | 'This feature was deprecated after v3.5.0-9.0.pre.' |
1593 | ) |
1594 | static bool boldTextOverride(BuildContext context) => boldTextOf(context); |
1595 | |
1596 | /// Returns the [MediaQueryData.boldText] accessibility setting for the |
1597 | /// nearest [MediaQuery] ancestor or null, if no such ancestor exists. |
1598 | /// |
1599 | /// Use of this method will cause the given [context] to rebuild any time that |
1600 | /// the [MediaQueryData.boldText] property of the ancestor [MediaQuery] |
1601 | /// changes. |
1602 | /// |
1603 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1604 | static bool? maybeBoldTextOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.boldText)?.boldText; |
1605 | |
1606 | /// Returns [MediaQueryData.navigationMode] for the nearest [MediaQuery] |
1607 | /// ancestor or throws an exception, if no such ancestor exists. |
1608 | /// |
1609 | /// Use of this method will cause the given [context] to rebuild any time that |
1610 | /// the [MediaQueryData.navigationMode] property of the ancestor [MediaQuery] |
1611 | /// changes. |
1612 | /// |
1613 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1614 | static NavigationMode navigationModeOf(BuildContext context) => _of(context, _MediaQueryAspect.navigationMode).navigationMode; |
1615 | |
1616 | /// Returns [MediaQueryData.navigationMode] for the nearest [MediaQuery] |
1617 | /// ancestor or null, if no such ancestor exists. |
1618 | /// |
1619 | /// Use of this method will cause the given [context] to rebuild any time that |
1620 | /// the [MediaQueryData.navigationMode] property of the ancestor [MediaQuery] |
1621 | /// changes. |
1622 | /// |
1623 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1624 | static NavigationMode? maybeNavigationModeOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.navigationMode)?.navigationMode; |
1625 | |
1626 | /// Returns [MediaQueryData.gestureSettings] for the nearest [MediaQuery] |
1627 | /// ancestor or throws an exception, if no such ancestor exists. |
1628 | /// |
1629 | /// Use of this method will cause the given [context] to rebuild any time that |
1630 | /// the [MediaQueryData.gestureSettings] property of the ancestor [MediaQuery] |
1631 | /// changes. |
1632 | /// |
1633 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1634 | static DeviceGestureSettings gestureSettingsOf(BuildContext context) => _of(context, _MediaQueryAspect.gestureSettings).gestureSettings; |
1635 | |
1636 | /// Returns [MediaQueryData.gestureSettings] for the nearest [MediaQuery] |
1637 | /// ancestor or null, if no such ancestor exists. |
1638 | /// |
1639 | /// Use of this method will cause the given [context] to rebuild any time that |
1640 | /// the [MediaQueryData.gestureSettings] property of the ancestor [MediaQuery] |
1641 | /// changes. |
1642 | /// |
1643 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1644 | static DeviceGestureSettings? maybeGestureSettingsOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.gestureSettings)?.gestureSettings; |
1645 | |
1646 | /// Returns [MediaQueryData.displayFeatures] for the nearest [MediaQuery] |
1647 | /// ancestor or throws an exception, if no such ancestor exists. |
1648 | /// |
1649 | /// Use of this method will cause the given [context] to rebuild any time that |
1650 | /// the [MediaQueryData.displayFeatures] property of the ancestor [MediaQuery] |
1651 | /// changes. |
1652 | /// |
1653 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf} |
1654 | static List<ui.DisplayFeature> displayFeaturesOf(BuildContext context) => _of(context, _MediaQueryAspect.displayFeatures).displayFeatures; |
1655 | |
1656 | /// Returns [MediaQueryData.displayFeatures] for the nearest [MediaQuery] |
1657 | /// ancestor or null, if no such ancestor exists. |
1658 | /// |
1659 | /// Use of this method will cause the given [context] to rebuild any time that |
1660 | /// the [MediaQueryData.displayFeatures] property of the ancestor [MediaQuery] |
1661 | /// changes. |
1662 | /// |
1663 | /// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf} |
1664 | static List<ui.DisplayFeature>? maybeDisplayFeaturesOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.displayFeatures)?.displayFeatures; |
1665 | |
1666 | @override |
1667 | bool updateShouldNotify(MediaQuery oldWidget) => data != oldWidget.data; |
1668 | |
1669 | @override |
1670 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
1671 | super.debugFillProperties(properties); |
1672 | properties.add(DiagnosticsProperty<MediaQueryData>('data' , data, showName: false)); |
1673 | } |
1674 | |
1675 | @override |
1676 | bool updateShouldNotifyDependent(MediaQuery oldWidget, Set<Object> dependencies) { |
1677 | for (final Object dependency in dependencies) { |
1678 | if (dependency is _MediaQueryAspect) { |
1679 | switch (dependency) { |
1680 | case _MediaQueryAspect.size: |
1681 | if (data.size != oldWidget.data.size) { |
1682 | return true; |
1683 | } |
1684 | case _MediaQueryAspect.orientation: |
1685 | if (data.orientation != oldWidget.data.orientation) { |
1686 | return true; |
1687 | } |
1688 | case _MediaQueryAspect.devicePixelRatio: |
1689 | if (data.devicePixelRatio != oldWidget.data.devicePixelRatio) { |
1690 | return true; |
1691 | } |
1692 | case _MediaQueryAspect.textScaleFactor: |
1693 | if (data.textScaleFactor != oldWidget.data.textScaleFactor) { |
1694 | return true; |
1695 | } |
1696 | case _MediaQueryAspect.textScaler: |
1697 | if (data.textScaler != oldWidget.data.textScaler) { |
1698 | return true; |
1699 | } |
1700 | case _MediaQueryAspect.platformBrightness: |
1701 | if (data.platformBrightness != oldWidget.data.platformBrightness) { |
1702 | return true; |
1703 | } |
1704 | case _MediaQueryAspect.padding: |
1705 | if (data.padding != oldWidget.data.padding) { |
1706 | return true; |
1707 | } |
1708 | case _MediaQueryAspect.viewInsets: |
1709 | if (data.viewInsets != oldWidget.data.viewInsets) { |
1710 | return true; |
1711 | } |
1712 | case _MediaQueryAspect.systemGestureInsets: |
1713 | if (data.systemGestureInsets != oldWidget.data.systemGestureInsets) { |
1714 | return true; |
1715 | } |
1716 | case _MediaQueryAspect.viewPadding: |
1717 | if (data.viewPadding != oldWidget.data.viewPadding) { |
1718 | return true; |
1719 | } |
1720 | case _MediaQueryAspect.alwaysUse24HourFormat: |
1721 | if (data.alwaysUse24HourFormat != oldWidget.data.alwaysUse24HourFormat) { |
1722 | return true; |
1723 | } |
1724 | case _MediaQueryAspect.accessibleNavigation: |
1725 | if (data.accessibleNavigation != oldWidget.data.accessibleNavigation) { |
1726 | return true; |
1727 | } |
1728 | case _MediaQueryAspect.invertColors: |
1729 | if (data.invertColors != oldWidget.data.invertColors) { |
1730 | return true; |
1731 | } |
1732 | case _MediaQueryAspect.highContrast: |
1733 | if (data.highContrast != oldWidget.data.highContrast) { |
1734 | return true; |
1735 | } |
1736 | case _MediaQueryAspect.onOffSwitchLabels: |
1737 | if (data.onOffSwitchLabels != oldWidget.data.onOffSwitchLabels) { |
1738 | return true; |
1739 | } |
1740 | case _MediaQueryAspect.disableAnimations: |
1741 | if (data.disableAnimations != oldWidget.data.disableAnimations) { |
1742 | return true; |
1743 | } |
1744 | case _MediaQueryAspect.boldText: |
1745 | if (data.boldText != oldWidget.data.boldText) { |
1746 | return true; |
1747 | } |
1748 | case _MediaQueryAspect.navigationMode: |
1749 | if (data.navigationMode != oldWidget.data.navigationMode) { |
1750 | return true; |
1751 | } |
1752 | case _MediaQueryAspect.gestureSettings: |
1753 | if (data.gestureSettings != oldWidget.data.gestureSettings) { |
1754 | return true; |
1755 | } |
1756 | case _MediaQueryAspect.displayFeatures: |
1757 | if (data.displayFeatures != oldWidget.data.displayFeatures) { |
1758 | return true; |
1759 | } |
1760 | } |
1761 | } |
1762 | } |
1763 | return false; |
1764 | } |
1765 | } |
1766 | |
1767 | /// Describes the navigation mode to be set by a [MediaQuery] widget. |
1768 | /// |
1769 | /// The different modes indicate the type of navigation to be used in a widget |
1770 | /// subtree for those widgets sensitive to it. |
1771 | /// |
1772 | /// Use `MediaQuery.navigationModeOf(context)` to determine the navigation mode |
1773 | /// in effect for the given context. Use a [MediaQuery] widget to set the |
1774 | /// navigation mode for its descendant widgets. |
1775 | enum NavigationMode { |
1776 | /// This indicates a traditional keyboard-and-mouse navigation modality. |
1777 | /// |
1778 | /// This navigation mode is where the arrow keys can be used for secondary |
1779 | /// modification operations, like moving sliders or cursors, and disabled |
1780 | /// controls will lose focus and not be traversable. |
1781 | traditional, |
1782 | |
1783 | /// This indicates a directional-based navigation mode. |
1784 | /// |
1785 | /// This navigation mode indicates that arrow keys should be reserved for |
1786 | /// navigation operations, and secondary modifications operations, like moving |
1787 | /// sliders or cursors, will use alternative bindings or be disabled. |
1788 | /// |
1789 | /// Some behaviors are also affected by this mode. For instance, disabled |
1790 | /// controls will retain focus when disabled, and will be able to receive |
1791 | /// focus (although they remain disabled) when traversed. |
1792 | directional, |
1793 | } |
1794 | |
1795 | class _MediaQueryFromView extends StatefulWidget { |
1796 | const _MediaQueryFromView({ |
1797 | super.key, |
1798 | required this.view, |
1799 | this.ignoreParentData = false, |
1800 | required this.child, |
1801 | }); |
1802 | |
1803 | final FlutterView view; |
1804 | final bool ignoreParentData; |
1805 | final Widget child; |
1806 | |
1807 | @override |
1808 | State<_MediaQueryFromView> createState() => _MediaQueryFromViewState(); |
1809 | } |
1810 | |
1811 | class _MediaQueryFromViewState extends State<_MediaQueryFromView> with WidgetsBindingObserver { |
1812 | MediaQueryData? _parentData; |
1813 | MediaQueryData? _data; |
1814 | |
1815 | @override |
1816 | void initState() { |
1817 | super.initState(); |
1818 | WidgetsBinding.instance.addObserver(this); |
1819 | } |
1820 | |
1821 | @override |
1822 | void didChangeDependencies() { |
1823 | super.didChangeDependencies(); |
1824 | _updateParentData(); |
1825 | _updateData(); |
1826 | assert(_data != null); |
1827 | } |
1828 | |
1829 | @override |
1830 | void didUpdateWidget(_MediaQueryFromView oldWidget) { |
1831 | super.didUpdateWidget(oldWidget); |
1832 | if (widget.ignoreParentData != oldWidget.ignoreParentData) { |
1833 | _updateParentData(); |
1834 | } |
1835 | if (_data == null || oldWidget.view != widget.view) { |
1836 | _updateData(); |
1837 | } |
1838 | assert(_data != null); |
1839 | } |
1840 | |
1841 | void _updateParentData() { |
1842 | _parentData = widget.ignoreParentData ? null : MediaQuery.maybeOf(context); |
1843 | _data = null; // _updateData must be called again after changing parent data. |
1844 | } |
1845 | |
1846 | void _updateData() { |
1847 | final MediaQueryData newData = MediaQueryData.fromView(widget.view, platformData: _parentData); |
1848 | if (newData != _data) { |
1849 | setState(() { |
1850 | _data = newData; |
1851 | }); |
1852 | } |
1853 | } |
1854 | |
1855 | @override |
1856 | void didChangeAccessibilityFeatures() { |
1857 | // If we have a parent, it dictates our accessibility features. If we don't |
1858 | // have a parent, we get our accessibility features straight from the |
1859 | // PlatformDispatcher and need to update our data in response to the |
1860 | // PlatformDispatcher changing its accessibility features setting. |
1861 | if (_parentData == null) { |
1862 | _updateData(); |
1863 | } |
1864 | } |
1865 | |
1866 | @override |
1867 | void didChangeMetrics() { |
1868 | _updateData(); |
1869 | } |
1870 | |
1871 | @override |
1872 | void didChangeTextScaleFactor() { |
1873 | // If we have a parent, it dictates our text scale factor. If we don't have |
1874 | // a parent, we get our text scale factor from the PlatformDispatcher and |
1875 | // need to update our data in response to the PlatformDispatcher changing |
1876 | // its text scale factor setting. |
1877 | if (_parentData == null) { |
1878 | _updateData(); |
1879 | } |
1880 | } |
1881 | |
1882 | @override |
1883 | void didChangePlatformBrightness() { |
1884 | // If we have a parent, it dictates our platform brightness. If we don't |
1885 | // have a parent, we get our platform brightness from the PlatformDispatcher |
1886 | // and need to update our data in response to the PlatformDispatcher |
1887 | // changing its platform brightness setting. |
1888 | if (_parentData == null) { |
1889 | _updateData(); |
1890 | } |
1891 | } |
1892 | |
1893 | @override |
1894 | void dispose() { |
1895 | WidgetsBinding.instance.removeObserver(this); |
1896 | super.dispose(); |
1897 | } |
1898 | |
1899 | @override |
1900 | Widget build(BuildContext context) { |
1901 | MediaQueryData effectiveData = _data!; |
1902 | // If we get our platformBrightness from the PlatformDispatcher (i.e. we have no parentData) replace it |
1903 | // with the debugBrightnessOverride in non-release mode. |
1904 | if (!kReleaseMode && _parentData == null && effectiveData.platformBrightness != debugBrightnessOverride) { |
1905 | effectiveData = effectiveData.copyWith(platformBrightness: debugBrightnessOverride); |
1906 | } |
1907 | return MediaQuery( |
1908 | data: effectiveData, |
1909 | child: widget.child, |
1910 | ); |
1911 | } |
1912 | } |
1913 | |
1914 | const TextScaler _kUnspecifiedTextScaler = _UnspecifiedTextScaler(); |
1915 | // TODO(LongCatIsLooong): Remove once `MediaQueryData.textScaleFactor` is |
1916 | // removed: https://github.com/flutter/flutter/issues/128825. |
1917 | class _UnspecifiedTextScaler implements TextScaler { |
1918 | const _UnspecifiedTextScaler(); |
1919 | |
1920 | @override |
1921 | TextScaler clamp({double minScaleFactor = 0, double maxScaleFactor = double.infinity}) => throw UnimplementedError(); |
1922 | |
1923 | @override |
1924 | double scale(double fontSize) => throw UnimplementedError(); |
1925 | |
1926 | @override |
1927 | double get textScaleFactor => throw UnimplementedError(); |
1928 | } |
1929 | |