@@ -138,8 +138,8 @@ enum _MediaQueryAspect {
138
138
class MediaQueryData {
139
139
/// Creates data for a media query with explicit values.
140
140
///
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 ] .
143
143
const MediaQueryData ({
144
144
this .size = Size .zero,
145
145
this .devicePixelRatio = 1.0 ,
@@ -167,24 +167,60 @@ class MediaQueryData {
167
167
/// window's metrics change. For example, see
168
168
/// [WidgetsBindingObserver.didChangeMetrics] or
169
169
/// [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;
188
224
189
225
/// The size of the media in logical pixels (e.g, the size of the screen).
190
226
///
@@ -889,17 +925,43 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> {
889
925
/// and its dependents are updated when `window` changes, instead of
890
926
/// rebuilding the whole widget tree.
891
927
///
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
- ///
896
928
/// The [child] argument is required and must not be null.
897
929
static Widget fromWindow ({
898
930
Key ? key,
899
931
required Widget child,
900
932
}) {
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 (
902
963
key: key,
964
+ view: view,
903
965
child: child,
904
966
);
905
967
}
@@ -1399,99 +1461,121 @@ enum NavigationMode {
1399
1461
directional,
1400
1462
}
1401
1463
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 ({
1423
1466
super .key,
1467
+ required this .view,
1468
+ this .ignoreParentData = false ,
1424
1469
required this .child,
1425
1470
});
1426
1471
1427
- /// {@macro flutter.widgets.ProxyWidget.child}
1472
+ final FlutterView view;
1473
+ final bool ignoreParentData;
1428
1474
final Widget child;
1429
1475
1430
1476
@override
1431
- State <_MediaQueryFromWindow > createState () => _MediaQueryFromWindowState ();
1477
+ State <_MediaQueryFromView > createState () => _MediaQueryFromViewState ();
1432
1478
}
1433
1479
1434
- class _MediaQueryFromWindowState extends State <_MediaQueryFromWindow > with WidgetsBindingObserver {
1480
+ class _MediaQueryFromViewState extends State <_MediaQueryFromView > with WidgetsBindingObserver {
1481
+ MediaQueryData ? _parentData;
1482
+ MediaQueryData ? _data;
1483
+
1435
1484
@override
1436
1485
void initState () {
1437
1486
super .initState ();
1438
1487
WidgetsBinding .instance.addObserver (this );
1439
1488
}
1440
1489
1441
- // ACCESSIBILITY
1490
+ @override
1491
+ void didChangeDependencies () {
1492
+ super .didChangeDependencies ();
1493
+ _updateParentData ();
1494
+ _updateData ();
1495
+ assert (_data != null );
1496
+ }
1442
1497
1443
1498
@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.
1449
1513
}
1450
1514
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
+ }
1452
1534
1453
1535
@override
1454
1536
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 ();
1459
1538
}
1460
1539
1461
1540
@override
1462
1541
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
+ }
1468
1549
}
1469
1550
1470
- // RENDERING
1471
1551
@override
1472
1552
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 ();
1478
1566
}
1479
1567
1480
1568
@override
1481
1569
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);
1485
1575
}
1486
1576
return MediaQuery (
1487
- data: data ,
1577
+ data: effectiveData ,
1488
1578
child: widget.child,
1489
1579
);
1490
1580
}
1491
-
1492
- @override
1493
- void dispose () {
1494
- WidgetsBinding .instance.removeObserver (this );
1495
- super .dispose ();
1496
- }
1497
1581
}
0 commit comments