diff --git a/packages/flutter/lib/src/material/snack_bar.dart b/packages/flutter/lib/src/material/snack_bar.dart index 5929aa7150..a6dc33b90f 100644 --- a/packages/flutter/lib/src/material/snack_bar.dart +++ b/packages/flutter/lib/src/material/snack_bar.dart @@ -140,15 +140,20 @@ class _SnackBarActionState extends State { final SnackBarThemeData snackBarTheme = Theme.of(context).snackBarTheme; MaterialStateColor resolveForegroundColor() { - if (widget.textColor is MaterialStateColor) { - return widget.textColor! as MaterialStateColor; - } - if (snackBarTheme.actionTextColor is MaterialStateColor) { - return snackBarTheme.actionTextColor! as MaterialStateColor; - } - if (defaults.actionTextColor is MaterialStateColor) { - return defaults.actionTextColor! as MaterialStateColor; + if (widget.textColor != null) { + if (widget.textColor is MaterialStateColor) { + return widget.textColor! as MaterialStateColor; + } + } else if (snackBarTheme.actionTextColor != null) { + if (snackBarTheme.actionTextColor is MaterialStateColor) { + return snackBarTheme.actionTextColor! as MaterialStateColor; + } + } else if (defaults.actionTextColor != null) { + if (defaults.actionTextColor is MaterialStateColor) { + return defaults.actionTextColor! as MaterialStateColor; + } } + return MaterialStateColor.resolveWith((Set states) { if (states.contains(MaterialState.disabled)) { return widget.disabledTextColor ?? diff --git a/packages/flutter/test/material/snack_bar_test.dart b/packages/flutter/test/material/snack_bar_test.dart index cbd65422cd..29ead0a1da 100644 --- a/packages/flutter/test/material/snack_bar_test.dart +++ b/packages/flutter/test/material/snack_bar_test.dart @@ -812,7 +812,7 @@ void main() { expect(snackBarBottomRight.dx, (800 + widgetWidth) / 2); // Device width is 800. }); - testWidgets('Snackbar labels can be colored', (WidgetTester tester) async { + testWidgets('Snackbar labels can be colored as MaterialColor (Material 2)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -856,6 +856,110 @@ void main() { } }); + testWidgets('Snackbar labels can be colored as MaterialColor (Material 3)', + (WidgetTester tester) async { + const MaterialColor usedColor = Colors.teal; + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('I am a snack bar.'), + duration: const Duration(seconds: 2), + action: SnackBarAction( + textColor: usedColor, + label: 'ACTION', + onPressed: () {}, + ), + ), + ); + }, + child: const Text('X'), + ); + }, + ), + ), + ), + ); + + await tester.tap(find.text('X')); + await tester.pump(); // start animation + await tester.pump(const Duration(milliseconds: 750)); + + final Element actionTextButton = + tester.element(find.widgetWithText(TextButton, 'ACTION')); + final Widget textButton = actionTextButton.widget; + if (textButton is TextButton) { + final ButtonStyle buttonStyle = textButton.style!; + if (buttonStyle.foregroundColor is MaterialStateColor) { + // Same color when resolved + expect(buttonStyle.foregroundColor!.resolve({}), usedColor); + } else { + expect(false, true); + } + } else { + expect(false, true); + } + }); + + testWidgets('Snackbar labels can be colored as MaterialStateColor (Material 3)', + (WidgetTester tester) async { + const _TestMaterialStateColor usedColor = _TestMaterialStateColor(); + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('I am a snack bar.'), + duration: const Duration(seconds: 2), + action: SnackBarAction( + textColor: usedColor, + label: 'ACTION', + onPressed: () {}, + ), + ), + ); + }, + child: const Text('X'), + ); + }, + ), + ), + ), + ); + + await tester.tap(find.text('X')); + await tester.pump(); // start animation + await tester.pump(const Duration(milliseconds: 750)); + + final Element actionTextButton = + tester.element(find.widgetWithText(TextButton, 'ACTION')); + final Widget textButton = actionTextButton.widget; + if (textButton is TextButton) { + final ButtonStyle buttonStyle = textButton.style!; + if (buttonStyle.foregroundColor is MaterialStateColor) { + // Exactly the same object + expect(buttonStyle.foregroundColor, usedColor); + } else { + expect(false, true); + } + } else { + expect(false, true); + } + }); + testWidgets('SnackBar button text alignment', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( @@ -2588,3 +2692,19 @@ Map> _getDragGesturesOfDismissDirections(double s return dragGestures; } + +class _TestMaterialStateColor extends MaterialStateColor { + const _TestMaterialStateColor() : super(_colorRed); + + static const int _colorRed = 0xFFF44336; + static const int _colorBlue = 0xFF2196F3; + + @override + Color resolve(Set states) { + if (states.contains(MaterialState.pressed)) { + return const Color(_colorBlue); + } + + return const Color(_colorRed); + } +}