diff --git a/packages/flutter/lib/src/material/toggle_buttons.dart b/packages/flutter/lib/src/material/toggle_buttons.dart index 2c3bdcc8f8..66d29e20e6 100644 --- a/packages/flutter/lib/src/material/toggle_buttons.dart +++ b/packages/flutter/lib/src/material/toggle_buttons.dart @@ -165,6 +165,7 @@ class ToggleButtons extends StatelessWidget { @required this.children, @required this.isSelected, this.onPressed, + this.textStyle, this.color, this.selectedColor, this.disabledColor, @@ -215,6 +216,13 @@ class ToggleButtons extends StatelessWidget { /// When the callback is null, all toggle buttons will be disabled. final void Function(int index) onPressed; + /// The [TextStyle] to apply to any text in these toggle buttons. + /// + /// [TextStyle.color] will be ignored and substituted by [color], + /// [selectedColor] or [disabledColor] depending on whether the buttons + /// are active, selected, or disabled. + final TextStyle textStyle; + /// The color for descendant [Text] and [Icon] widgets if the button is /// enabled and not selected. /// @@ -569,6 +577,7 @@ class ToggleButtons extends StatelessWidget { return _ToggleButton( selected: isSelected[index], + textStyle: textStyle, color: color, selectedColor: selectedColor, disabledColor: disabledColor, @@ -603,6 +612,7 @@ class ToggleButtons extends StatelessWidget { ifTrue: 'Buttons are disabled', ifFalse: 'Buttons are enabled', )); + textStyle?.debugFillProperties(properties, prefix: 'textStyle.'); properties.add(ColorProperty('color', color, defaultValue: null)); properties.add(ColorProperty('selectedColor', selectedColor, defaultValue: null)); properties.add(ColorProperty('disabledColor', disabledColor, defaultValue: null)); @@ -634,6 +644,7 @@ class _ToggleButton extends StatelessWidget { const _ToggleButton({ Key key, this.selected = false, + this.textStyle, this.color, this.selectedColor, this.disabledColor, @@ -657,6 +668,9 @@ class _ToggleButton extends StatelessWidget { /// Determines if the button is displayed as active/selected or enabled. final bool selected; + /// The [TextStyle] to apply to any text that appears in this button. + final TextStyle textStyle; + /// The color for [Text] and [Icon] widgets if the button is enabled. /// /// If [selected] is false and [onPressed] is not null, this color will be used. @@ -769,10 +783,12 @@ class _ToggleButton extends StatelessWidget { currentFillColor = theme.colorScheme.surface.withOpacity(0.0); } + final TextStyle currentTextStyle = textStyle ?? toggleButtonsTheme.textStyle ?? theme.textTheme.body1; + final Widget result = ClipRRect( borderRadius: clipRadius, child: RawMaterialButton( - textStyle: TextStyle( + textStyle: currentTextStyle.copyWith( color: currentColor, ), elevation: 0.0, diff --git a/packages/flutter/lib/src/material/toggle_buttons_theme.dart b/packages/flutter/lib/src/material/toggle_buttons_theme.dart index 66c8b40b27..7bc27608af 100644 --- a/packages/flutter/lib/src/material/toggle_buttons_theme.dart +++ b/packages/flutter/lib/src/material/toggle_buttons_theme.dart @@ -28,6 +28,7 @@ class ToggleButtonsThemeData extends Diagnosticable { /// Creates the set of color and border properties used to configure /// [ToggleButtons]. const ToggleButtonsThemeData({ + this.textStyle, this.color, this.selectedColor, this.disabledColor, @@ -43,6 +44,13 @@ class ToggleButtonsThemeData extends Diagnosticable { this.borderWidth, }); + /// The default text style for [ToggleButtons.children]. + /// + /// [TextStyle.color] will be ignored and substituted by [color], + /// [selectedColor] or [disabledColor] depending on whether the buttons + /// are active, selected, or disabled. + final TextStyle textStyle; + /// The color for descendant [Text] and [Icon] widgets if the toggle button /// is enabled. final Color color; @@ -95,6 +103,7 @@ class ToggleButtonsThemeData extends Diagnosticable { /// Creates a copy of this object but with the given fields replaced with the /// new values. ToggleButtonsThemeData copyWith({ + TextStyle textStyle, Color color, Color selectedColor, Color disabledColor, @@ -110,6 +119,7 @@ class ToggleButtonsThemeData extends Diagnosticable { double borderWidth, }) { return ToggleButtonsThemeData( + textStyle: textStyle ?? this.textStyle, color: color ?? this.color, selectedColor: selectedColor ?? this.selectedColor, disabledColor: disabledColor ?? this.disabledColor, @@ -132,6 +142,7 @@ class ToggleButtonsThemeData extends Diagnosticable { if (a == null && b == null) return null; return ToggleButtonsThemeData( + textStyle: TextStyle.lerp(a?.textStyle, b?.textStyle, t), color: Color.lerp(a?.color, b?.color, t), selectedColor: Color.lerp(a?.selectedColor, b?.selectedColor, t), disabledColor: Color.lerp(a?.disabledColor, b?.disabledColor, t), @@ -151,6 +162,7 @@ class ToggleButtonsThemeData extends Diagnosticable { @override int get hashCode { return hashValues( + textStyle, color, selectedColor, disabledColor, @@ -174,7 +186,8 @@ class ToggleButtonsThemeData extends Diagnosticable { if (other.runtimeType != runtimeType) return false; final ToggleButtonsThemeData typedOther = other; - return typedOther.color == color + return typedOther.textStyle == textStyle + && typedOther.color == color && typedOther.selectedColor == selectedColor && typedOther.disabledColor == disabledColor && typedOther.fillColor == fillColor @@ -192,6 +205,7 @@ class ToggleButtonsThemeData extends Diagnosticable { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); + textStyle?.debugFillProperties(properties, prefix: 'textStyle.'); properties.add(ColorProperty('color', color, defaultValue: null)); properties.add(ColorProperty('selectedColor', selectedColor, defaultValue: null)); properties.add(ColorProperty('disabledColor', disabledColor, defaultValue: null)); diff --git a/packages/flutter/test/material/toggle_buttons_test.dart b/packages/flutter/test/material/toggle_buttons_test.dart index 929e187a4a..0fdd120315 100644 --- a/packages/flutter/test/material/toggle_buttons_test.dart +++ b/packages/flutter/test/material/toggle_buttons_test.dart @@ -250,6 +250,78 @@ void main() { }, ); + testWidgets('Default text style is applied', (WidgetTester tester) async { + final ThemeData theme = ThemeData(); + await tester.pumpWidget( + Material( + child: boilerplate( + child: ToggleButtons( + isSelected: const [false, true], + onPressed: (int index) {}, + children: const [ + Text('First child'), + Text('Second child'), + ], + ), + ), + ), + ); + + TextStyle textStyle; + textStyle = tester.widget(find.descendant( + of: find.widgetWithText(RawMaterialButton, 'First child'), + matching: find.byType(DefaultTextStyle), + )).style; + expect(textStyle.fontFamily, theme.textTheme.body1.fontFamily); + expect(textStyle.decoration, theme.textTheme.body1.decoration); + + textStyle = tester.widget(find.descendant( + of: find.widgetWithText(RawMaterialButton, 'Second child'), + matching: find.byType(DefaultTextStyle), + )).style; + expect(textStyle.fontFamily, theme.textTheme.body1.fontFamily); + expect(textStyle.decoration, theme.textTheme.body1.decoration); + }); + + testWidgets('Custom text style except color is applied', (WidgetTester tester) async { + await tester.pumpWidget( + Material( + child: boilerplate( + child: ToggleButtons( + isSelected: const [false, true], + onPressed: (int index) {}, + textStyle: const TextStyle( + textBaseline: TextBaseline.ideographic, + fontSize: 20.0, + color: Colors.orange, + ), + children: const [ + Text('First child'), + Text('Second child'), + ], + ), + ), + ), + ); + + TextStyle textStyle; + textStyle = tester.widget(find.descendant( + of: find.widgetWithText(RawMaterialButton, 'First child'), + matching: find.byType(DefaultTextStyle), + )).style; + expect(textStyle.textBaseline, TextBaseline.ideographic); + expect(textStyle.fontSize, 20.0); + expect(textStyle.color, isNot(Colors.orange)); + + textStyle = tester.widget(find.descendant( + of: find.widgetWithText(RawMaterialButton, 'Second child'), + matching: find.byType(DefaultTextStyle), + )).style; + expect(textStyle.textBaseline, TextBaseline.ideographic); + expect(textStyle.fontSize, 20.0); + expect(textStyle.color, isNot(Colors.orange)); + }); + testWidgets( 'Default text/icon colors for enabled, selected and disabled states', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/toggle_buttons_theme_test.dart b/packages/flutter/test/material/toggle_buttons_theme_test.dart index 1b15806cf3..bbe24f1cb2 100644 --- a/packages/flutter/test/material/toggle_buttons_theme_test.dart +++ b/packages/flutter/test/material/toggle_buttons_theme_test.dart @@ -24,6 +24,7 @@ void main() { test('ToggleButtonsThemeData defaults', () { const ToggleButtonsThemeData themeData = ToggleButtonsThemeData(); + expect(themeData.textStyle, null); expect(themeData.color, null); expect(themeData.selectedColor, null); expect(themeData.disabledColor, null); @@ -39,6 +40,7 @@ void main() { expect(themeData.borderWidth, null); const ToggleButtonsTheme theme = ToggleButtonsTheme(data: ToggleButtonsThemeData()); + expect(theme.data.textStyle, null); expect(theme.data.color, null); expect(theme.data.selectedColor, null); expect(theme.data.disabledColor, null); @@ -69,6 +71,7 @@ void main() { testWidgets('ToggleButtonsThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ToggleButtonsThemeData( + textStyle: TextStyle(fontSize: 10), color: Color(0xfffffff0), selectedColor: Color(0xfffffff1), disabledColor: Color(0xfffffff2), @@ -90,6 +93,8 @@ void main() { .toList(); expect(description, [ + 'textStyle.inherit: true', + 'textStyle.size: 10.0', 'color: Color(0xfffffff0)', 'selectedColor: Color(0xfffffff1)', 'disabledColor: Color(0xfffffff2)', @@ -106,6 +111,49 @@ void main() { ]); }); + testWidgets('Theme text style, except color, is applied', (WidgetTester tester) async { + await tester.pumpWidget( + Material( + child: boilerplate( + child: ToggleButtonsTheme( + data: const ToggleButtonsThemeData( + textStyle: TextStyle( + color: Colors.orange, + textBaseline: TextBaseline.ideographic, + fontSize: 20.0, + ), + ), + child: ToggleButtons( + isSelected: const [false, true], + onPressed: (int index) {}, + children: const [ + Text('First child'), + Text('Second child'), + ], + ), + ), + ), + ), + ); + + TextStyle textStyle; + textStyle = tester.widget(find.descendant( + of: find.widgetWithText(RawMaterialButton, 'First child'), + matching: find.byType(DefaultTextStyle), + )).style; + expect(textStyle.textBaseline, TextBaseline.ideographic); + expect(textStyle.fontSize, 20.0); + expect(textStyle.color, isNot(Colors.orange)); + + textStyle = tester.widget(find.descendant( + of: find.widgetWithText(RawMaterialButton, 'Second child'), + matching: find.byType(DefaultTextStyle), + )).style; + expect(textStyle.textBaseline, TextBaseline.ideographic); + expect(textStyle.fontSize, 20.0); + expect(textStyle.color, isNot(Colors.orange)); + }); + testWidgets( 'Theme text/icon colors for enabled, selected and disabled states', (WidgetTester tester) async {