diff --git a/packages/flutter/lib/src/material/banner.dart b/packages/flutter/lib/src/material/banner.dart index 3573a108632..7ff0a5c9079 100644 --- a/packages/flutter/lib/src/material/banner.dart +++ b/packages/flutter/lib/src/material/banner.dart @@ -17,6 +17,7 @@ import 'theme.dart'; const Duration _materialBannerTransitionDuration = Duration(milliseconds: 250); const Curve _materialBannerHeightCurve = Curves.fastOutSlowIn; +const double _kMaxContentTextScaleFactor = 1.5; /// Specify how a [MaterialBanner] was closed. /// @@ -365,21 +366,31 @@ class _MaterialBannerState extends State { padding: leadingPadding, child: widget.leading, ), - Expanded( - child: DefaultTextStyle( - style: textStyle!, - child: widget.content, + MediaQuery.withClampedTextScaling( + // Set maximum text scale factor to _kMaxContentTextScaleFactor for the + // content to keep the visual hierarchy the same even with larger font + // sizes. + maxScaleFactor: _kMaxContentTextScaleFactor, + child: Expanded( + child: DefaultTextStyle( + style: textStyle!, + child: widget.content, + ), ), ), if (isSingleRow) - actionsBar, + MediaQuery.withClampedTextScaling( + // Set maximum text scale factor to _kMaxContentTextScaleFactor for the + // actionsBar to keep the visual hierarchy the same even with larger font + // sizes. + maxScaleFactor: _kMaxContentTextScaleFactor, + child: actionsBar, + ), ], ), ), - if (!isSingleRow) - actionsBar, - if (elevation == 0) - Divider(height: 0, color: dividerColor), + if (!isSingleRow) actionsBar, + if (elevation == 0) Divider(height: 0, color: dividerColor), ], ), ), diff --git a/packages/flutter/test/material/banner_test.dart b/packages/flutter/test/material/banner_test.dart index 77e222bd303..65bb5a8ef46 100644 --- a/packages/flutter/test/material/banner_test.dart +++ b/packages/flutter/test/material/banner_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -236,6 +237,51 @@ void main() { expect(contentBottomLeft.dx, lessThan(actionsTopRight.dx)); }); + testWidgets('material banner content can scale and has maxScaleFactor', (WidgetTester tester) async { + + const String label = 'A'; + Widget buildApp({ required TextScaler textScaler }) { + return MaterialApp( + home: MediaQuery( + data: MediaQueryData(textScaler: textScaler), + child: MaterialBanner( + forceActionsBelow: true, + content: const SizedBox(child:Center(child:Text(label))), + actions: [ + TextButton( + child: const Text('B'), + onPressed: () { }, + ), + ], + ), + ), + ); + } + + await tester.pumpWidget(buildApp(textScaler: TextScaler.noScaling)); + expect(find.text(label), findsOneWidget); + + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(tester.getSize(find.text(label)), const Size(14.25, 20.0)); + } + + await tester.pumpWidget(buildApp(textScaler: const TextScaler.linear(1.1))); + await tester.pumpAndSettle(); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(_sizeAlmostEqual(tester.getSize(find.text(label)), const Size(15.65, 22.0)), true); + } + + await tester.pumpWidget(buildApp(textScaler: const TextScaler.linear(1.5))); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(_sizeAlmostEqual(tester.getSize(find.text(label)), const Size(21.25, 30)), true); + } + + await tester.pumpWidget(buildApp(textScaler: const TextScaler.linear(4))); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(_sizeAlmostEqual(tester.getSize(find.text(label)), const Size(21.25, 30)), true); + } + }); + group('MaterialBanner elevation', () { Widget buildBanner(Key tapTarget, {double? elevation, double? themeElevation}) { return MaterialApp( @@ -1117,3 +1163,7 @@ Material _getMaterialFromText(WidgetTester tester, String text) { RenderParagraph _getTextRenderObjectFromDialog(WidgetTester tester, String text) { return tester.element(find.descendant(of: find.byType(MaterialBanner), matching: find.text(text))).renderObject! as RenderParagraph; } + +bool _sizeAlmostEqual(Size a, Size b, {double maxDiff=0.05}) { + return (a.width - b.width).abs() <= maxDiff && (a.height - b.height).abs() <= maxDiff; +}