Skip to content

Commit c781b31

Browse files
authored
Add height and width aspects to MediaQuery. (flutter#167829)
<!-- Thanks for filing a pull request! Reviewers are typically assigned within a week of filing a request. To learn more about code review, see our documentation on Tree Hygiene: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md --> Closes flutter#167828 ### Description - Adds `widthOf`, `maybeWidthOf`, `heightOf`, `maybeHeightOf` functions to `MediaQuery` - Adds tests for newly added functions ## Pre-launch Checklist - [X] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [X] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [X] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [X] I signed the [CLA]. - [X] I listed at least one issue that this PR fixes in the description above. - [X] I updated/added relevant documentation (doc comments with `///`). - [X] I added new tests to check the change I am making, or this PR is [test-exempt]. - [X] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [X] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
1 parent ed447e5 commit c781b31

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed

packages/flutter/lib/src/widgets/media_query.dart

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ enum _MediaQueryAspect {
4949
/// Specifies the aspect corresponding to [MediaQueryData.size].
5050
size,
5151

52+
/// Specifies the aspect corresponding to the width of [MediaQueryData.size].
53+
width,
54+
55+
/// Specifies the aspect corresponding to the height of [MediaQueryData.size].
56+
height,
57+
5258
/// Specifies the aspect corresponding to [MediaQueryData.orientation].
5359
orientation,
5460

@@ -1306,6 +1312,49 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> {
13061312
/// {@endtemplate}
13071313
static Size? maybeSizeOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.size)?.size;
13081314

1315+
/// Returns width of [MediaQueryData.size] from the nearest [MediaQuery]
1316+
/// ancestor or throws an exception, if no such ancestor exists.
1317+
///
1318+
/// Use of this method will cause the given [context] to rebuild any time that
1319+
/// the width of [MediaQueryData.size] property of the ancestor [MediaQuery]
1320+
/// changes.
1321+
///
1322+
/// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf}
1323+
static double widthOf(BuildContext context) => _of(context, _MediaQueryAspect.width).size.width;
1324+
1325+
/// Returns width of [MediaQueryData.size] from the nearest [MediaQuery]
1326+
/// ancestor or null, if no such ancestor exists.
1327+
///
1328+
/// Use of this method will cause the given [context] to rebuild any time that
1329+
/// the width of [MediaQueryData.size] property of the ancestor [MediaQuery]
1330+
/// changes.
1331+
///
1332+
/// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf}
1333+
static double? maybeWidthOf(BuildContext context) =>
1334+
_maybeOf(context, _MediaQueryAspect.width)?.size.width;
1335+
1336+
/// Returns height of [MediaQueryData.size] from the nearest [MediaQuery]
1337+
/// ancestor or throws an exception, if no such ancestor exists.
1338+
///
1339+
/// Use of this method will cause the given [context] to rebuild any time that
1340+
/// the height of [MediaQueryData.size] property of the ancestor [MediaQuery]
1341+
/// changes.
1342+
///
1343+
/// {@macro flutter.widgets.media_query.MediaQuery.dontUseOf}
1344+
static double heightOf(BuildContext context) =>
1345+
_of(context, _MediaQueryAspect.height).size.height;
1346+
1347+
/// Returns height of [MediaQueryData.size] from the nearest [MediaQuery]
1348+
/// ancestor or null, if no such ancestor exists.
1349+
///
1350+
/// Use of this method will cause the given [context] to rebuild any time that
1351+
/// the height of [MediaQueryData.size] property of the ancestor [MediaQuery]
1352+
/// changes.
1353+
///
1354+
/// {@macro flutter.widgets.media_query.MediaQuery.dontUseMaybeOf}
1355+
static double? maybeHeightOf(BuildContext context) =>
1356+
_maybeOf(context, _MediaQueryAspect.height)?.size.height;
1357+
13091358
/// Returns [MediaQueryData.orientation] for the nearest [MediaQuery] ancestor or
13101359
/// throws an exception, if no such ancestor exists.
13111360
///
@@ -1776,6 +1825,8 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> {
17761825
dependency is _MediaQueryAspect &&
17771826
switch (dependency) {
17781827
_MediaQueryAspect.size => data.size != oldWidget.data.size,
1828+
_MediaQueryAspect.width => data.size.width != oldWidget.data.size.width,
1829+
_MediaQueryAspect.height => data.size.height != oldWidget.data.size.height,
17791830
_MediaQueryAspect.orientation => data.orientation != oldWidget.data.orientation,
17801831
_MediaQueryAspect.devicePixelRatio =>
17811832
data.devicePixelRatio != oldWidget.data.devicePixelRatio,

packages/flutter/test/widgets/media_query_test.dart

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,6 +1576,10 @@ void main() {
15761576
values: <_MediaQueryAspectCase>[
15771577
const _MediaQueryAspectCase(MediaQuery.sizeOf, MediaQueryData(size: Size(1, 1))),
15781578
const _MediaQueryAspectCase(MediaQuery.maybeSizeOf, MediaQueryData(size: Size(1, 1))),
1579+
const _MediaQueryAspectCase(MediaQuery.widthOf, MediaQueryData(size: Size(1, 0))),
1580+
const _MediaQueryAspectCase(MediaQuery.maybeWidthOf, MediaQueryData(size: Size(1, 0))),
1581+
const _MediaQueryAspectCase(MediaQuery.heightOf, MediaQueryData(size: Size(0, 1))),
1582+
const _MediaQueryAspectCase(MediaQuery.maybeHeightOf, MediaQueryData(size: Size(0, 1))),
15791583
const _MediaQueryAspectCase(MediaQuery.orientationOf, MediaQueryData(size: Size(2, 1))),
15801584
const _MediaQueryAspectCase(
15811585
MediaQuery.maybeOrientationOf,
@@ -1732,4 +1736,79 @@ void main() {
17321736
],
17331737
),
17341738
);
1739+
1740+
testWidgets('MediaQuery width and height can be listened to independently', (
1741+
WidgetTester tester,
1742+
) async {
1743+
MediaQueryData data = const MediaQueryData(size: Size(800, 600));
1744+
1745+
int widthBuildCount = 0;
1746+
int heightBuildCount = 0;
1747+
1748+
final Widget showWidth = Builder(
1749+
builder: (BuildContext context) {
1750+
widthBuildCount++;
1751+
return Text('width: ${MediaQuery.widthOf(context).toStringAsFixed(1)}');
1752+
},
1753+
);
1754+
1755+
final Widget showHeight = Builder(
1756+
builder: (BuildContext context) {
1757+
heightBuildCount++;
1758+
return Text('height: ${MediaQuery.heightOf(context).toStringAsFixed(1)}');
1759+
},
1760+
);
1761+
1762+
final Widget page = StatefulBuilder(
1763+
builder: (BuildContext context, StateSetter setState) {
1764+
return MediaQuery(
1765+
data: data,
1766+
child: Center(
1767+
child: Column(
1768+
children: <Widget>[
1769+
showWidth,
1770+
showHeight,
1771+
ElevatedButton(
1772+
onPressed: () {
1773+
setState(() {
1774+
data = data.copyWith(size: Size(data.size.width + 100, data.size.height));
1775+
});
1776+
},
1777+
child: const Text('Increase width by 100'),
1778+
),
1779+
ElevatedButton(
1780+
onPressed: () {
1781+
setState(() {
1782+
data = data.copyWith(size: Size(data.size.width, data.size.height + 100));
1783+
});
1784+
},
1785+
child: const Text('Increase height by 100'),
1786+
),
1787+
],
1788+
),
1789+
),
1790+
);
1791+
},
1792+
);
1793+
1794+
await tester.pumpWidget(MaterialApp(home: page));
1795+
expect(find.text('width: 800.0'), findsOneWidget);
1796+
expect(find.text('height: 600.0'), findsOneWidget);
1797+
expect(widthBuildCount, 1);
1798+
expect(heightBuildCount, 1);
1799+
1800+
await tester.tap(find.text('Increase width by 100'));
1801+
await tester.pumpAndSettle();
1802+
expect(find.text('width: 900.0'), findsOneWidget);
1803+
expect(find.text('height: 600.0'), findsOneWidget);
1804+
expect(widthBuildCount, 2);
1805+
expect(heightBuildCount, 1);
1806+
1807+
await tester.tap(find.text('Increase height by 100'));
1808+
await tester.pumpAndSettle();
1809+
expect(find.text('width: 900.0'), findsOneWidget);
1810+
expect(find.text('height: 700.0'), findsOneWidget);
1811+
expect(widthBuildCount, 2);
1812+
expect(heightBuildCount, 2);
1813+
});
17351814
}

0 commit comments

Comments
 (0)