diff --git a/packages/material_ui/lib/src/snack_bar.dart b/packages/material_ui/lib/src/snack_bar.dart index 9a7180d86c6..9ea49ecf52c 100644 --- a/packages/material_ui/lib/src/snack_bar.dart +++ b/packages/material_ui/lib/src/snack_bar.dart @@ -721,9 +721,9 @@ class _SnackBarState extends State { icon: const Icon(Icons.close), iconSize: 24.0, color: widget.closeIconColor ?? snackBarTheme.closeIconColor ?? defaults.closeIconColor, - onPressed: () => ScaffoldMessenger.of( - context, - ).hideCurrentSnackBar(reason: SnackBarClosedReason.dismiss), + onPressed: () => + ScaffoldMessenger.of(context) + .hideCurrentSnackBar(reason: SnackBarClosedReason.dismiss), tooltip: MaterialLocalizations.of(context).closeButtonTooltip, ) : null; @@ -736,6 +736,7 @@ class _SnackBarState extends State { ), maxLines: 1, textDirection: TextDirection.ltr, + textScaler: MediaQuery.textScalerOf(context), )..layout(); final double actionAndIconWidth = actionTextPainter.size.width + @@ -793,7 +794,6 @@ class _SnackBarState extends State { ), ), if (!willOverflowAction) ...maybeActionAndIcon, - if (willOverflowAction) SizedBox(width: snackBarWidth * 0.4), ], ), if (willOverflowAction) diff --git a/packages/material_ui/pending_changelogs/change_snack_bar_text_scaler.yaml b/packages/material_ui/pending_changelogs/change_snack_bar_text_scaler.yaml new file mode 100644 index 00000000000..6ab87e54149 --- /dev/null +++ b/packages/material_ui/pending_changelogs/change_snack_bar_text_scaler.yaml @@ -0,0 +1,3 @@ +changelog: | + - Accounts for `MediaQuery`'s `TextScaler` when calculating `SnackBar` action overflow and removes unnecessary blank right spacing in multi-line layout. +version: patch diff --git a/packages/material_ui/test/snack_bar_test.dart b/packages/material_ui/test/snack_bar_test.dart index 6949ee8bee9..870e2dfabb7 100644 --- a/packages/material_ui/test/snack_bar_test.dart +++ b/packages/material_ui/test/snack_bar_test.dart @@ -4445,6 +4445,103 @@ Future _testSnackBarDismiss({ expect(find.text('bar2'), findsNothing); } } + + testWidgets('SnackBar action overflow calculation respects MediaQuery textScaler', ( + WidgetTester tester, + ) async { + Widget buildSnackBar({required TextScaler textScaler}) { + return MaterialApp( + home: MediaQuery( + data: MediaQueryData(size: const Size(400, 800), textScaler: textScaler), + child: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('Message'), + action: SnackBarAction(label: 'Action Label', onPressed: () {}), + ), + ); + }, + child: const Text('Show'), + ); + }, + ), + ), + ), + ); + } + + // With no scaling, the action label fits on the same row as content. + await tester.pumpWidget(buildSnackBar(textScaler: TextScaler.noScaling)); + await tester.tap(find.text('Show')); + await tester.pumpAndSettle(); + + final Offset actionTopLeft1 = tester.getTopLeft(find.text('Action Label')); + // Action and content are on the same line (action is not below content). + expect(actionTopLeft1.dy, lessThanOrEqualTo(tester.getBottomLeft(find.text('Message')).dy)); + + ScaffoldMessenger.of(tester.element(find.text('Show'))).clearSnackBars(); + await tester.pumpAndSettle(); + + // With a large text scaler, the action button width is scaled up and overflows + // to a separate row below the content. + await tester.pumpWidget(buildSnackBar(textScaler: const TextScaler.linear(3.0))); + await tester.tap(find.text('Show')); + await tester.pumpAndSettle(); + + final Offset contentBottomLeft2 = tester.getBottomLeft(find.text('Message')); + final Offset actionTopLeft2 = tester.getTopLeft(find.text('Action Label')); + // Action overflows and is positioned below the content text. + expect(actionTopLeft2.dy, greaterThanOrEqualTo(contentBottomLeft2.dy)); + }); + + testWidgets('SnackBar does not allocate 40% empty space on right when action overflows', ( + WidgetTester tester, + ) async { + const double screenWidth = 500.0; + await tester.pumpWidget( + MaterialApp( + home: MediaQuery( + data: const MediaQueryData(size: Size(screenWidth, 800)), + child: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('Multi-line content that wraps'), + action: SnackBarAction(label: 'Overflow Action', onPressed: () {}), + actionOverflowThreshold: 0.1, + ), + ); + }, + child: const Text('Show'), + ); + }, + ), + ), + ), + ), + ); + + await tester.tap(find.text('Show')); + await tester.pumpAndSettle(); + + // Verify there is no SizedBox with width equal to 40% of snackBarWidth. + expect( + find.byWidgetPredicate( + (Widget widget) => + widget is SizedBox && + widget.width != null && + (widget.width! - screenWidth * 0.4).abs() < 1.0, + ), + findsNothing, + ); + }); } /// Create drag gestures for DismissDirections.