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

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com