From 86a2613ceed9bb609b84af4949c0ff687a2137fc Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Wed, 8 May 2024 09:34:05 +0200 Subject: [PATCH] Fix floating SnackBar is not centered when RTL and Material 2 (#147861) ## Description This PR fixes floating `SnackBar` positioning when the text direction is RTL and the theme uses Material 2. In https://github.com/flutter/flutter/pull/140215, I fixed the `SnackBar` position for M3/RTL, but while doing so I broke the positioning for M2/RTL... Unfortunately, there was no existing test for this case. The solution is to not rely on `TextDirection` to compute the `SnackBar` position: the `SnackBar` is centered in both cases so the text direction has no impact on its positioning (it had some impact in the `SnackBar` content, but this is managed correctly). ## Related Issue Fixes https://github.com/flutter/flutter/issues/147838. ## Tests Adds 1 test. --- .../flutter/lib/src/material/scaffold.dart | 8 +--- .../flutter/lib/src/material/snack_bar.dart | 2 +- .../flutter/test/material/snack_bar_test.dart | 48 ++++++++++++++++++- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart index 23a512c74feb..dccacc32907f 100644 --- a/packages/flutter/lib/src/material/scaffold.dart +++ b/packages/flutter/lib/src/material/scaffold.dart @@ -1217,13 +1217,7 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { : contentBottom; } - double xOffset = 0.0; - if (hasCustomWidth) { - xOffset = switch (textDirection) { - TextDirection.rtl => (snackBarWidth! - size.width) / 2, - TextDirection.ltr => (size.width - snackBarWidth!) / 2, - }; - } + final double xOffset = hasCustomWidth ? (size.width - snackBarWidth!) / 2 : 0.0; positionChild(_ScaffoldSlot.snackBar, Offset(xOffset, snackBarYOffsetBase - snackBarSize.height)); assert((){ diff --git a/packages/flutter/lib/src/material/snack_bar.dart b/packages/flutter/lib/src/material/snack_bar.dart index 78e1b2eb81ee..ac4d4b2e8774 100644 --- a/packages/flutter/lib/src/material/snack_bar.dart +++ b/packages/flutter/lib/src/material/snack_bar.dart @@ -819,7 +819,7 @@ class _SnackBarState extends State { animation: heightM3Animation, builder: (BuildContext context, Widget? child) { return Align( - alignment: AlignmentDirectional.bottomStart, + alignment: Alignment.bottomLeft, heightFactor: heightM3Animation.value, child: child, ); diff --git a/packages/flutter/test/material/snack_bar_test.dart b/packages/flutter/test/material/snack_bar_test.dart index c35f1e26d5b2..105d197d7c60 100644 --- a/packages/flutter/test/material/snack_bar_test.dart +++ b/packages/flutter/test/material/snack_bar_test.dart @@ -2601,7 +2601,7 @@ void main() { }, ); - testWidgets('Floating snackbar with custom width is centered when text direction is rtl', (WidgetTester tester) async { + testWidgets('Material3 - Floating snackbar with custom width is centered when text direction is rtl', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/140125. const double customWidth = 400.0; await tester.pumpWidget( @@ -2631,7 +2631,51 @@ void main() { ); await tester.tap(find.text('X')); - await tester.pump(); // start animation + await tester.pump(); // Start animation. + await tester.pump(const Duration(milliseconds: 750)); + + final Finder materialFinder = find.descendant( + of: find.byType(SnackBar), + matching: find.byType(Material), + ); + final Offset snackBarBottomLeft = tester.getBottomLeft(materialFinder); + final Offset snackBarBottomRight = tester.getBottomRight(materialFinder); + expect(snackBarBottomLeft.dx, (800 - customWidth) / 2); // Device width is 800. + expect(snackBarBottomRight.dx, (800 + customWidth) / 2); // Device width is 800. + }); + + testWidgets('Material2 - Floating snackbar with custom width is centered when text direction is rtl', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/147838. + const double customWidth = 400.0; + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: false), + home: Directionality( + textDirection: TextDirection.rtl, + child: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + behavior: SnackBarBehavior.floating, + width: customWidth, + content: Text('Feeling super snackish'), + ), + ); + }, + child: const Text('X'), + ); + }, + ), + ), + ), + ), + ); + + await tester.tap(find.text('X')); + await tester.pump(); // Start animation. await tester.pump(const Duration(milliseconds: 750)); final Finder materialFinder = find.descendant(