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
5import 'dart:math' as math;
6import 'dart:ui' as ui;
7
8import 'package:flutter/foundation.dart';
9import 'package:flutter/gestures.dart';
10
11import 'basic.dart';
12import 'binding.dart';
13import 'debug.dart';
14import 'framework.dart';
15import 'inherited_model.dart';
16
17// Examples can assume:
18// late BuildContext context;
19
20/// Whether in portrait or landscape.
21enum 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.
36enum _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
144class 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.
899class 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.
1775enum 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
1795class _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
1811class _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
1914const TextScaler _kUnspecifiedTextScaler = _UnspecifiedTextScaler();
1915// TODO(LongCatIsLooong): Remove once `MediaQueryData.textScaleFactor` is
1916// removed: https://github.com/flutter/flutter/issues/128825.
1917class _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