@@ -138,8 +138,8 @@ enum _MediaQueryAspect {
138138class MediaQueryData {
139139 /// Creates data for a media query with explicit values.
140140 ///
141- /// Consider using [MediaQueryData.fromWindow ] to create data based on a
142- /// [dart:ui.PlatformDispatcher ] .
141+ /// Consider using [MediaQueryData.fromView ] to create data based on a
142+ /// [dart:ui.FlutterView ] .
143143 const MediaQueryData ({
144144 this .size = Size .zero,
145145 this .devicePixelRatio = 1.0 ,
@@ -167,24 +167,60 @@ class MediaQueryData {
167167 /// window's metrics change. For example, see
168168 /// [WidgetsBindingObserver.didChangeMetrics] or
169169 /// [dart:ui.PlatformDispatcher.onMetricsChanged] .
170- MediaQueryData .fromWindow (ui.FlutterView window)
171- : size = window.physicalSize / window.devicePixelRatio,
172- devicePixelRatio = window.devicePixelRatio,
173- textScaleFactor = window.platformDispatcher.textScaleFactor,
174- platformBrightness = window.platformDispatcher.platformBrightness,
175- padding = EdgeInsets .fromWindowPadding (window.padding, window.devicePixelRatio),
176- viewPadding = EdgeInsets .fromWindowPadding (window.viewPadding, window.devicePixelRatio),
177- viewInsets = EdgeInsets .fromWindowPadding (window.viewInsets, window.devicePixelRatio),
178- systemGestureInsets = EdgeInsets .fromWindowPadding (window.systemGestureInsets, window.devicePixelRatio),
179- accessibleNavigation = window.platformDispatcher.accessibilityFeatures.accessibleNavigation,
180- invertColors = window.platformDispatcher.accessibilityFeatures.invertColors,
181- disableAnimations = window.platformDispatcher.accessibilityFeatures.disableAnimations,
182- boldText = window.platformDispatcher.accessibilityFeatures.boldText,
183- highContrast = window.platformDispatcher.accessibilityFeatures.highContrast,
184- alwaysUse24HourFormat = window.platformDispatcher.alwaysUse24HourFormat,
185- navigationMode = NavigationMode .traditional,
186- gestureSettings = DeviceGestureSettings .fromWindow (window),
187- displayFeatures = window.displayFeatures;
170+ factory MediaQueryData .fromWindow (ui.FlutterView window) => MediaQueryData .fromView (window);
171+
172+ /// Creates data for a [MediaQuery] based on the given `view` .
173+ ///
174+ /// If provided, the `platformData` is used to fill in the platform-specific
175+ /// aspects of the newly created [MediaQueryData] . If `platformData` is null,
176+ /// the `view` 's [PlatformDispatcher] is consulted to construct the
177+ /// platform-specific data.
178+ ///
179+ /// Data which is exposed directly on the [FlutterView] is considered
180+ /// view-specific. Data which is only exposed via the
181+ /// [FlutterView.platformDispatcher] property is considered platform-specific.
182+ ///
183+ /// Callers of this method should ensure that they also register for
184+ /// notifications so that the [MediaQueryData] can be updated when any data
185+ /// used to construct it changes. Notifications to consider are:
186+ ///
187+ /// * [WidgetsBindingObserver.didChangeMetrics] or
188+ /// [dart:ui.PlatformDispatcher.onMetricsChanged],
189+ /// * [WidgetsBindingObserver.didChangeAccessibilityFeatures] or
190+ /// [dart:ui.PlatformDispatcher.onAccessibilityFeaturesChanged],
191+ /// * [WidgetsBindingObserver.didChangeTextScaleFactor] or
192+ /// [dart:ui.PlatformDispatcher.onTextScaleFactorChanged],
193+ /// * [WidgetsBindingObserver.didChangePlatformBrightness] or
194+ /// [dart:ui.PlatformDispatcher.onPlatformBrightnessChanged].
195+ ///
196+ /// The last three notifications are only relevant if no `platformData` is
197+ /// provided. If `platformData` is provided, callers should ensure to call
198+ /// this method again when it changes to keep the constructed [MediaQueryData]
199+ /// updated.
200+ ///
201+ /// See also:
202+ ///
203+ /// * [MediaQuery.fromView] , which constructs [MediaQueryData] from a provided
204+ /// [FlutterView], makes it available to descendant widgets, and sets up
205+ /// the appropriate notification listeners to keep the data updated.
206+ MediaQueryData .fromView (ui.FlutterView view, {MediaQueryData ? platformData})
207+ : size = view.physicalSize / view.devicePixelRatio,
208+ devicePixelRatio = view.devicePixelRatio,
209+ textScaleFactor = platformData? .textScaleFactor ?? view.platformDispatcher.textScaleFactor,
210+ platformBrightness = platformData? .platformBrightness ?? view.platformDispatcher.platformBrightness,
211+ padding = EdgeInsets .fromWindowPadding (view.padding, view.devicePixelRatio),
212+ viewPadding = EdgeInsets .fromWindowPadding (view.viewPadding, view.devicePixelRatio),
213+ viewInsets = EdgeInsets .fromWindowPadding (view.viewInsets, view.devicePixelRatio),
214+ systemGestureInsets = EdgeInsets .fromWindowPadding (view.systemGestureInsets, view.devicePixelRatio),
215+ accessibleNavigation = platformData? .accessibleNavigation ?? view.platformDispatcher.accessibilityFeatures.accessibleNavigation,
216+ invertColors = platformData? .invertColors ?? view.platformDispatcher.accessibilityFeatures.invertColors,
217+ disableAnimations = platformData? .disableAnimations ?? view.platformDispatcher.accessibilityFeatures.disableAnimations,
218+ boldText = platformData? .boldText ?? view.platformDispatcher.accessibilityFeatures.boldText,
219+ highContrast = platformData? .highContrast ?? view.platformDispatcher.accessibilityFeatures.highContrast,
220+ alwaysUse24HourFormat = platformData? .alwaysUse24HourFormat ?? view.platformDispatcher.alwaysUse24HourFormat,
221+ navigationMode = platformData? .navigationMode ?? NavigationMode .traditional,
222+ gestureSettings = DeviceGestureSettings .fromWindow (view),
223+ displayFeatures = view.displayFeatures;
188224
189225 /// The size of the media in logical pixels (e.g, the size of the screen).
190226 ///
@@ -889,17 +925,43 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> {
889925 /// and its dependents are updated when `window` changes, instead of
890926 /// rebuilding the whole widget tree.
891927 ///
892- /// This should be inserted into the widget tree when the [MediaQuery] view
893- /// padding is consumed by a widget in such a way that the view padding is no
894- /// longer exposed to the widget's descendants or siblings.
895- ///
896928 /// The [child] argument is required and must not be null.
897929 static Widget fromWindow ({
898930 Key ? key,
899931 required Widget child,
900932 }) {
901- return _MediaQueryFromWindow (
933+ return _MediaQueryFromView (
934+ key: key,
935+ view: WidgetsBinding .instance.window,
936+ ignoreParentData: true ,
937+ child: child,
938+ );
939+ }
940+
941+ /// Wraps the [child] in a [MediaQuery] which is built using data from the
942+ /// provided [view] .
943+ ///
944+ /// The [MediaQuery] is constructed using the platform-specific data of the
945+ /// surrounding [MediaQuery] and the view-specific data of the provided
946+ /// [view] . If no surrounding [MediaQuery] exists, the platform-specific data
947+ /// is generated from the [PlatformDispatcher] associated with the provided
948+ /// [view] . Any information that's exposed via the [PlatformDispatcher] is
949+ /// considered platform-specific. Data exposed directly on the [FlutterView]
950+ /// (excluding its [FlutterView.platformDispatcher] property) is considered
951+ /// view-specific.
952+ ///
953+ /// The injected [MediaQuery] automatically updates when any of the data used
954+ /// to construct it changes.
955+ ///
956+ /// The [view] and [child] argument is required and must not be null.
957+ static Widget fromView ({
958+ Key ? key,
959+ required FlutterView view,
960+ required Widget child,
961+ }) {
962+ return _MediaQueryFromView (
902963 key: key,
964+ view: view,
903965 child: child,
904966 );
905967 }
@@ -1399,99 +1461,121 @@ enum NavigationMode {
13991461 directional,
14001462}
14011463
1402- /// Provides a [MediaQuery] which is built and updated using the latest
1403- /// [WidgetsBinding.window] values.
1404- ///
1405- /// Receives `window` updates by listening to [WidgetsBinding] .
1406- ///
1407- /// The standalone widget ensures that it rebuilds **only** [MediaQuery] and
1408- /// its dependents when `window` changes, instead of rebuilding the entire
1409- /// widget tree.
1410- ///
1411- /// It is used by [WidgetsApp] if no other [MediaQuery] is available above it.
1412- ///
1413- /// See also:
1414- ///
1415- /// * [MediaQuery] , which establishes a subtree in which media queries resolve
1416- /// to a [MediaQueryData].
1417- class _MediaQueryFromWindow extends StatefulWidget {
1418- /// Creates a [_MediaQueryFromWindow] that provides a [MediaQuery] to its
1419- /// descendants using the `window` to keep [MediaQueryData] up to date.
1420- ///
1421- /// The [child] must not be null.
1422- const _MediaQueryFromWindow ({
1464+ class _MediaQueryFromView extends StatefulWidget {
1465+ const _MediaQueryFromView ({
14231466 super .key,
1467+ required this .view,
1468+ this .ignoreParentData = false ,
14241469 required this .child,
14251470 });
14261471
1427- /// {@macro flutter.widgets.ProxyWidget.child}
1472+ final FlutterView view;
1473+ final bool ignoreParentData;
14281474 final Widget child;
14291475
14301476 @override
1431- State <_MediaQueryFromWindow > createState () => _MediaQueryFromWindowState ();
1477+ State <_MediaQueryFromView > createState () => _MediaQueryFromViewState ();
14321478}
14331479
1434- class _MediaQueryFromWindowState extends State <_MediaQueryFromWindow > with WidgetsBindingObserver {
1480+ class _MediaQueryFromViewState extends State <_MediaQueryFromView > with WidgetsBindingObserver {
1481+ MediaQueryData ? _parentData;
1482+ MediaQueryData ? _data;
1483+
14351484 @override
14361485 void initState () {
14371486 super .initState ();
14381487 WidgetsBinding .instance.addObserver (this );
14391488 }
14401489
1441- // ACCESSIBILITY
1490+ @override
1491+ void didChangeDependencies () {
1492+ super .didChangeDependencies ();
1493+ _updateParentData ();
1494+ _updateData ();
1495+ assert (_data != null );
1496+ }
14421497
14431498 @override
1444- void didChangeAccessibilityFeatures () {
1445- setState (() {
1446- // The properties of window have changed. We use them in our build
1447- // function, so we need setState(), but we don't cache anything locally.
1448- });
1499+ void didUpdateWidget (_MediaQueryFromView oldWidget) {
1500+ super .didUpdateWidget (oldWidget);
1501+ if (widget.ignoreParentData != oldWidget.ignoreParentData) {
1502+ _updateParentData ();
1503+ }
1504+ if (_data == null || oldWidget.view != widget.view) {
1505+ _updateData ();
1506+ }
1507+ assert (_data != null );
1508+ }
1509+
1510+ void _updateParentData () {
1511+ _parentData = widget.ignoreParentData ? null : MediaQuery .maybeOf (context);
1512+ _data = null ; // _updateData must be called again after changing parent data.
14491513 }
14501514
1451- // METRICS
1515+ void _updateData () {
1516+ final MediaQueryData newData = MediaQueryData .fromView (widget.view, platformData: _parentData);
1517+ if (newData != _data) {
1518+ setState (() {
1519+ _data = newData;
1520+ });
1521+ }
1522+ }
1523+
1524+ @override
1525+ void didChangeAccessibilityFeatures () {
1526+ // If we have a parent, it dictates our accessibility features. If we don't
1527+ // have a parent, we get our accessibility features straight from the
1528+ // PlatformDispatcher and need to update our data in response to the
1529+ // PlatformDispatcher changing its accessibility features setting.
1530+ if (_parentData == null ) {
1531+ _updateData ();
1532+ }
1533+ }
14521534
14531535 @override
14541536 void didChangeMetrics () {
1455- setState (() {
1456- // The properties of window have changed. We use them in our build
1457- // function, so we need setState(), but we don't cache anything locally.
1458- });
1537+ _updateData ();
14591538 }
14601539
14611540 @override
14621541 void didChangeTextScaleFactor () {
1463- setState (() {
1464- // The textScaleFactor property of window has changed. We reference
1465- // window in our build function, so we need to call setState(), but
1466- // we don't need to cache anything locally.
1467- });
1542+ // If we have a parent, it dictates our text scale factor. If we don't have
1543+ // a parent, we get our text scale factor from the PlatformDispatcher and
1544+ // need to update our data in response to the PlatformDispatcher changing
1545+ // its text scale factor setting.
1546+ if (_parentData == null ) {
1547+ _updateData ();
1548+ }
14681549 }
14691550
1470- // RENDERING
14711551 @override
14721552 void didChangePlatformBrightness () {
1473- setState (() {
1474- // The platformBrightness property of window has changed. We reference
1475- // window in our build function, so we need to call setState(), but
1476- // we don't need to cache anything locally.
1477- });
1553+ // If we have a parent, it dictates our platform brightness. If we don't
1554+ // have a parent, we get our platform brightness from the PlatformDispatcher
1555+ // and need to update our data in response to the PlatformDispatcher
1556+ // changing its platform brightness setting.
1557+ if (_parentData == null ) {
1558+ _updateData ();
1559+ }
1560+ }
1561+
1562+ @override
1563+ void dispose () {
1564+ WidgetsBinding .instance.removeObserver (this );
1565+ super .dispose ();
14781566 }
14791567
14801568 @override
14811569 Widget build (BuildContext context) {
1482- MediaQueryData data = MediaQueryData .fromWindow (WidgetsBinding .instance.window);
1483- if (! kReleaseMode) {
1484- data = data.copyWith (platformBrightness: debugBrightnessOverride);
1570+ MediaQueryData effectiveData = _data! ;
1571+ // If we get our platformBrightness from the PlatformDispatcher (i.e. we have no parentData) replace it
1572+ // with the debugBrightnessOverride in non-release mode.
1573+ if (! kReleaseMode && _parentData == null && effectiveData.platformBrightness != debugBrightnessOverride) {
1574+ effectiveData = effectiveData.copyWith (platformBrightness: debugBrightnessOverride);
14851575 }
14861576 return MediaQuery (
1487- data: data ,
1577+ data: effectiveData ,
14881578 child: widget.child,
14891579 );
14901580 }
1491-
1492- @override
1493- void dispose () {
1494- WidgetsBinding .instance.removeObserver (this );
1495- super .dispose ();
1496- }
14971581}
0 commit comments