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