From dae3a87d936e0addb6734ba00635112e03318e94 Mon Sep 17 00:00:00 2001 From: Jamie Kerber Date: Mon, 12 Aug 2024 21:26:39 +0200 Subject: [PATCH] Implemented CupertinoButton new styles/sizes (fixes #92525) (#152845) This PR fixes #92525 and introduces the following changes according to [latest iOS HIG](https://developer.apple.com/design/human-interface-guidelines/buttons#iOS-iPadOS): - `CupertinoButton` now has a `size` property (type `enum CupertinoButtonSize`, values sm/md/lg, default `lg`) that allows the devs to apply new iOS 15+ button styles - Previously `CupertinoButton` had a larger padding when no background color was specified. With the new HIG, that is no longer the case - `CupertinoButton` now has a `.tinted` constructor that renders a translucent background (transparency % is brightness-dependent) and uses a different foreground color compared to `.filled` - `CupertinoButton` now uses the `actionTextStyle` TextStyle from the given theme - `CupertinoButton`'s child IconTheme's size will always be x1.2 the given TextStyle's size - `CupertinoTextThemeData` now has a `actionSmallTextStyle` property to use with small buttons (including a default `_kDefaultActionSmallTextStyle` TextStyle) Preview & example: ![image](https://github.com/user-attachments/assets/0985eb19-c091-41f5-bd98-0de196b7e403) > **NOTE**: there is a discrepancy in dark mode button foreground color between the default CupertinoTheme and the HIG. A separate issue will be opened for this. ~EDIT: issue reported here https://github.com/flutter/flutter/issues/152846~ EDIT2: fixed by #153039 ! ![image](https://github.com/user-attachments/assets/d671d7b4-bb2f-4b38-9464-ee1b04927304) ## Example ```dart import 'package:flutter/cupertino.dart'; const Widget body = Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( CupertinoIcons.play_fill, ), Text("Play"), ], ); void main() => runApp( CupertinoApp( home: Container( child: Wrap( direction: Axis.horizontal, children: [ // header Text(''), Text('Plain'), Text('Grey'), Text('Tinted'), Text('Filled'), // small Text('Small'), CupertinoButton( child: body, onPressed: () {}, size: CupertinoButtonSize.small, ), CupertinoButton.tinted( child: body, onPressed: () {}, size: CupertinoButtonSize.small, color: CupertinoColors.systemGrey, ), CupertinoButton.tinted( child: body, onPressed: () {}, size: CupertinoButtonSize.small, ), CupertinoButton.filled( child: body, onPressed: () {}, size: CupertinoButtonSize.small, ), // medium Text('Medium'), CupertinoButton( child: body, onPressed: () {}, size: CupertinoButtonSize.medium, ), CupertinoButton.tinted( child: body, onPressed: () {}, size: CupertinoButtonSize.medium, color: CupertinoColors.systemGrey, ), CupertinoButton.tinted( child: body, onPressed: () {}, size: CupertinoButtonSize.medium, ), CupertinoButton.filled( child: body, onPressed: () {}, size: CupertinoButtonSize.medium, ), // large Text('Large'), CupertinoButton( child: body, onPressed: () {}, size: CupertinoButtonSize.large, ), CupertinoButton.tinted( child: body, onPressed: () {}, color: CupertinoColors.systemGrey, size: CupertinoButtonSize.large, ), CupertinoButton.tinted( child: body, onPressed: () {}, size: CupertinoButtonSize.large, ), CupertinoButton.filled( child: body, onPressed: () {}, size: CupertinoButtonSize.large, ), ].map((Widget w) => SizedBox(width: 110, height: 70, child: Center(child: w))).toList(), ), ) ), ); ``` *List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../editable_text_toolbar_builder.0.dart | 1 - .../flutter/lib/src/cupertino/button.dart | 133 ++++++++++++---- .../flutter/lib/src/cupertino/constants.dart | 56 +++++++ .../text_selection_toolbar_button.dart | 1 - .../flutter/lib/src/cupertino/text_theme.dart | 32 ++++ .../flutter/test/cupertino/button_test.dart | 146 ++++++++++++++---- .../test/cupertino/text_theme_test.dart | 6 + .../flutter/test/cupertino/theme_test.dart | 1 + 8 files changed, 314 insertions(+), 62 deletions(-) diff --git a/examples/api/lib/material/context_menu/editable_text_toolbar_builder.0.dart b/examples/api/lib/material/context_menu/editable_text_toolbar_builder.0.dart index 138c14d4689..96dd54fa78b 100644 --- a/examples/api/lib/material/context_menu/editable_text_toolbar_builder.0.dart +++ b/examples/api/lib/material/context_menu/editable_text_toolbar_builder.0.dart @@ -63,7 +63,6 @@ class _EditableTextToolbarBuilderExampleAppState extends State= 0.0 && pressedOpacity <= 1.0)), - _filled = false; + _style = _CupertinoButtonStyle.plain; + + /// Creates an iOS-style button with a tinted background. + /// + /// The background color is derived from the [CupertinoTheme]'s `primaryColor` + transparency. + /// The foreground color is the [CupertinoTheme]'s `primaryColor`. + /// + /// To specify a custom background color, use the [color] argument of the + /// default constructor. + /// + /// To match the iOS "grey" button style, set [color] to [CupertinoColors.systemGrey]. + const CupertinoButton.tinted({ + super.key, + required this.child, + this.sizeStyle = CupertinoButtonSize.large, + this.padding, + this.color, + this.disabledColor = CupertinoColors.tertiarySystemFill, + this.minSize, + this.pressedOpacity = 0.4, + this.borderRadius, + this.alignment = Alignment.center, + this.focusColor, + this.focusNode, + this.onFocusChange, + this.autofocus = false, + required this.onPressed, + }) : _style = _CupertinoButtonStyle.tinted; /// Creates an iOS-style button with a filled background. /// @@ -72,11 +119,12 @@ class CupertinoButton extends StatefulWidget { const CupertinoButton.filled({ super.key, required this.child, + this.sizeStyle = CupertinoButtonSize.large, this.padding, - this.disabledColor = CupertinoColors.quaternarySystemFill, - this.minSize = kMinInteractiveDimensionCupertino, + this.disabledColor = CupertinoColors.tertiarySystemFill, + this.minSize, this.pressedOpacity = 0.4, - this.borderRadius = const BorderRadius.all(Radius.circular(8.0)), + this.borderRadius, this.alignment = Alignment.center, this.focusColor, this.focusNode, @@ -85,7 +133,7 @@ class CupertinoButton extends StatefulWidget { required this.onPressed, }) : assert(pressedOpacity == null || (pressedOpacity >= 0.0 && pressedOpacity <= 1.0)), color = null, - _filled = true; + _style = _CupertinoButtonStyle.filled; /// The widget below this widget in the tree. /// @@ -133,9 +181,14 @@ class CupertinoButton extends StatefulWidget { /// The radius of the button's corners when it has a background color. /// - /// Defaults to round corners of 8 logical pixels. + /// Defaults to [kCupertinoButtonSizeBorderRadius], based on [sizeStyle]. final BorderRadius? borderRadius; + /// The size of the button. + /// + /// Defaults to [CupertinoButtonSize.large]. + final CupertinoButtonSize sizeStyle; + /// The alignment of the button's [child]. /// /// Typically buttons are sized to be just big enough to contain the child and its @@ -166,7 +219,7 @@ class CupertinoButton extends StatefulWidget { /// {@macro flutter.widgets.Focus.autofocus} final bool autofocus; - final bool _filled; + final _CupertinoButtonStyle _style; /// Whether the button is enabled or disabled. Buttons are disabled by default. To /// enable a button, set its [onPressed] property to a non-null value. @@ -273,15 +326,24 @@ class _CupertinoButtonState extends State with SingleTickerProv final bool enabled = widget.enabled; final CupertinoThemeData themeData = CupertinoTheme.of(context); final Color primaryColor = themeData.primaryColor; - final Color? backgroundColor = widget.color == null - ? (widget._filled ? primaryColor : null) - : CupertinoDynamicColor.maybeResolve(widget.color, context); - - final Color foregroundColor = backgroundColor != null + final Color? backgroundColor = ( + widget.color == null + ? widget._style != _CupertinoButtonStyle.plain + ? primaryColor + : null + : CupertinoDynamicColor.maybeResolve(widget.color, context) + )?.withOpacity( + widget._style == _CupertinoButtonStyle.tinted + ? CupertinoTheme.brightnessOf(context) == Brightness.light + ? kCupertinoButtonTintedOpacityLight + : kCupertinoButtonTintedOpacityDark + : widget.color?.opacity ?? 1.0, + ); + final Color foregroundColor = widget._style == _CupertinoButtonStyle.filled ? themeData.primaryContrastingColor : enabled ? primaryColor - : CupertinoDynamicColor.resolve(CupertinoColors.placeholderText, context); + : CupertinoDynamicColor.resolve(CupertinoColors.tertiaryLabel, context); final Color effectiveFocusOutlineColor = widget.focusColor ?? HSLColor @@ -291,8 +353,17 @@ class _CupertinoButtonState extends State with SingleTickerProv .withSaturation(kCupertinoFocusColorSaturation) .toColor(); - final TextStyle textStyle = themeData.textTheme.textStyle.copyWith(color: foregroundColor); - final IconThemeData iconTheme = IconTheme.of(context).copyWith(color: foregroundColor); + final TextStyle textStyle = ( + widget.sizeStyle == CupertinoButtonSize.small + ? themeData.textTheme.actionSmallTextStyle + : themeData.textTheme.actionTextStyle + ).copyWith(color: foregroundColor); + final IconThemeData iconTheme = IconTheme.of(context).copyWith( + color: foregroundColor, + size: textStyle.fontSize != null + ? textStyle.fontSize! * 1.2 + : kCupertinoButtonDefaultIconSize, + ); return MouseRegion( cursor: enabled && kIsWeb ? SystemMouseCursors.click : MouseCursor.defer, @@ -311,12 +382,10 @@ class _CupertinoButtonState extends State with SingleTickerProv child: Semantics( button: true, child: ConstrainedBox( - constraints: widget.minSize == null - ? const BoxConstraints() - : BoxConstraints( - minWidth: widget.minSize!, - minHeight: widget.minSize!, - ), + constraints: BoxConstraints( + minWidth: widget.minSize ?? kCupertinoButtonMinSize[widget.sizeStyle] ?? kMinInteractiveDimensionCupertino, + minHeight: widget.minSize ?? kCupertinoButtonMinSize[widget.sizeStyle] ?? kMinInteractiveDimensionCupertino, + ), child: FadeTransition( opacity: _opacityAnimation, child: DecoratedBox( @@ -330,15 +399,13 @@ class _CupertinoButtonState extends State with SingleTickerProv ), ) : null, - borderRadius: widget.borderRadius, + borderRadius: widget.borderRadius ?? kCupertinoButtonSizeBorderRadius[widget.sizeStyle], color: backgroundColor != null && !enabled ? CupertinoDynamicColor.resolve(widget.disabledColor, context) : backgroundColor, ), child: Padding( - padding: widget.padding ?? (backgroundColor != null - ? _kBackgroundButtonPadding - : _kButtonPadding), + padding: widget.padding ?? kCupertinoButtonPadding[widget.sizeStyle]!, child: Align( alignment: widget.alignment, widthFactor: 1.0, diff --git a/packages/flutter/lib/src/cupertino/constants.dart b/packages/flutter/lib/src/cupertino/constants.dart index c7d10716832..2ed80d1866e 100644 --- a/packages/flutter/lib/src/cupertino/constants.dart +++ b/packages/flutter/lib/src/cupertino/constants.dart @@ -5,6 +5,10 @@ /// @docImport 'package:flutter/material.dart'; library; +import 'package:flutter/widgets.dart'; + +import 'button.dart'; + /// The minimum dimension of any interactive region according to the iOS Human /// Interface Guidelines. /// @@ -31,3 +35,55 @@ const double kMinInteractiveDimensionCupertino = 44.0; const double kCupertinoFocusColorOpacity = 0.80, kCupertinoFocusColorBrightness = 0.69, kCupertinoFocusColorSaturation = 0.835; + +/// Opacity values for the background of a [CupertinoButton.tinted]. +/// +/// See also: +/// +/// * +const double kCupertinoButtonTintedOpacityLight = 0.12, + kCupertinoButtonTintedOpacityDark = 0.26; + +/// The default value for [IconThemeData.size] of [CupertinoButton.child]. +/// +/// Set to match the most-frequent size of icons in iOS (matches md/lg). +/// +/// Used only when the [CupertinoTextThemeData.actionTextStyle] or [CupertinoTextThemeData.actionSmallTextStyle] +/// has a null [TextStyle.fontSize]. +const double kCupertinoButtonDefaultIconSize = 20.0; + +/// The padding values for the different [CupertinoButtonSize]s. +/// +/// Based on the iOS (17) [Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/buttons#iOS-iPadOS). +const Map kCupertinoButtonPadding = { + CupertinoButtonSize.small: EdgeInsets.symmetric( + vertical: 6, + horizontal: 12, + ), + CupertinoButtonSize.medium: EdgeInsets.symmetric( + vertical: 10, + horizontal: 15, + ), + CupertinoButtonSize.large: EdgeInsets.symmetric( + vertical: 16, + horizontal: 20, + ), +}; + +/// The border radius values for the different [CupertinoButtonSize]s. +/// +/// Based on the iOS (17) [Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/buttons#iOS-iPadOS). +final Map kCupertinoButtonSizeBorderRadius = { + CupertinoButtonSize.small: BorderRadius.circular(40), + CupertinoButtonSize.medium: BorderRadius.circular(40), + CupertinoButtonSize.large: BorderRadius.circular(12), +}; + +/// The minimum size of a [CupertinoButton] based on the [CupertinoButtonSize]. +/// +/// Based on the iOS (17) [Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/buttons#iOS-iPadOS). +const Map kCupertinoButtonMinSize = { + CupertinoButtonSize.small: 28, + CupertinoButtonSize.medium: 32, + CupertinoButtonSize.large: 44, +}; diff --git a/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart b/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart index 1507f3073ee..f8173334541 100644 --- a/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart +++ b/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart @@ -133,7 +133,6 @@ class _CupertinoTextSelectionToolbarButtonState extends State _tabLabelTextStyle ?? _defaults.tabLabelTextStyle; @@ -216,6 +241,7 @@ class CupertinoTextThemeData with Diagnosticable { CupertinoDynamicColor.maybeResolve(_primaryColor, context), _resolveTextStyle(_textStyle, context), _resolveTextStyle(_actionTextStyle, context), + _resolveTextStyle(_actionSmallTextStyle, context), _resolveTextStyle(_tabLabelTextStyle, context), _resolveTextStyle(_navTitleTextStyle, context), _resolveTextStyle(_navLargeTitleTextStyle, context), @@ -231,6 +257,7 @@ class CupertinoTextThemeData with Diagnosticable { Color? primaryColor, TextStyle? textStyle, TextStyle? actionTextStyle, + TextStyle? actionSmallTextStyle, TextStyle? tabLabelTextStyle, TextStyle? navTitleTextStyle, TextStyle? navLargeTitleTextStyle, @@ -243,6 +270,7 @@ class CupertinoTextThemeData with Diagnosticable { primaryColor ?? _primaryColor, textStyle ?? _textStyle, actionTextStyle ?? _actionTextStyle, + actionSmallTextStyle ?? _actionSmallTextStyle, tabLabelTextStyle ?? _tabLabelTextStyle, navTitleTextStyle ?? _navTitleTextStyle, navLargeTitleTextStyle ?? _navLargeTitleTextStyle, @@ -258,6 +286,7 @@ class CupertinoTextThemeData with Diagnosticable { const CupertinoTextThemeData defaultData = CupertinoTextThemeData(); properties.add(DiagnosticsProperty('textStyle', textStyle, defaultValue: defaultData.textStyle)); properties.add(DiagnosticsProperty('actionTextStyle', actionTextStyle, defaultValue: defaultData.actionTextStyle)); + properties.add(DiagnosticsProperty('actionSmallTextStyle', actionSmallTextStyle, defaultValue: defaultData.actionSmallTextStyle)); properties.add(DiagnosticsProperty('tabLabelTextStyle', tabLabelTextStyle, defaultValue: defaultData.tabLabelTextStyle)); properties.add(DiagnosticsProperty('navTitleTextStyle', navTitleTextStyle, defaultValue: defaultData.navTitleTextStyle)); properties.add(DiagnosticsProperty('navLargeTitleTextStyle', navLargeTitleTextStyle, defaultValue: defaultData.navLargeTitleTextStyle)); @@ -279,6 +308,7 @@ class CupertinoTextThemeData with Diagnosticable { && other._primaryColor == _primaryColor && other._textStyle == _textStyle && other._actionTextStyle == _actionTextStyle + && other._actionSmallTextStyle == _actionSmallTextStyle && other._tabLabelTextStyle == _tabLabelTextStyle && other._navTitleTextStyle == _navTitleTextStyle && other._navLargeTitleTextStyle == _navLargeTitleTextStyle @@ -293,6 +323,7 @@ class CupertinoTextThemeData with Diagnosticable { _primaryColor, _textStyle, _actionTextStyle, + _actionSmallTextStyle, _tabLabelTextStyle, _navTitleTextStyle, _navLargeTitleTextStyle, @@ -327,6 +358,7 @@ class _TextThemeDefaultsBuilder { TextStyle get dateTimePickerTextStyle => _applyLabelColor(_kDefaultDateTimePickerTextStyle, labelColor); TextStyle actionTextStyle({ Color? primaryColor }) => _kDefaultActionTextStyle.copyWith(color: primaryColor); + TextStyle actionSmallTextStyle({ Color? primaryColor }) => _kDefaultActionSmallTextStyle.copyWith(color: primaryColor); TextStyle navActionTextStyle({ Color? primaryColor }) => actionTextStyle(primaryColor: primaryColor); _TextThemeDefaultsBuilder resolveFrom(BuildContext context) { diff --git a/packages/flutter/test/cupertino/button_test.dart b/packages/flutter/test/cupertino/button_test.dart index 8cc9887d8ff..d2e3a4d5e95 100644 --- a/packages/flutter/test/cupertino/button_test.dart +++ b/packages/flutter/test/cupertino/button_test.dart @@ -27,8 +27,8 @@ void main() { final RenderBox buttonBox = tester.renderObject(find.byType(CupertinoButton)); expect( buttonBox.size, - // 1 10px character + 16px * 2 is smaller than the default 44px minimum. - const Size.square(44.0), + // 1 10px character + 20px * 2 = 50.0 + const Size(50.0, 44.0), ); }); @@ -44,7 +44,7 @@ void main() { final RenderBox buttonBox = tester.renderObject(find.byType(CupertinoButton)); expect( buttonBox.size, - // 1 10px character + 16px * 2 is smaller than defined 60.0px minimum + // 1 10px character + 20px * 2 = 50.0 (is smaller than minSize: 60.0) const Size.square(minSize), ); }); @@ -59,8 +59,8 @@ void main() { final RenderBox buttonBox = tester.renderObject(find.byType(CupertinoButton)); expect( buttonBox.size.width, - // 4 10px character + 16px * 2 = 72. - 72.0, + // 4 10px character + 20px * 2 = 80.0 + 80.0, ); }); @@ -129,17 +129,37 @@ void main() { expect(align.alignment, Alignment.centerLeft); }); - testWidgets('Button with background is wider', (WidgetTester tester) async { + testWidgets('Button size changes depending on size property', (WidgetTester tester) async { + const Widget child = Text('X', style: testStyle); + await tester.pumpWidget(boilerplate(child: const CupertinoButton( onPressed: null, - color: Color(0xFFFFFFFF), - child: Text('X', style: testStyle), + sizeStyle: CupertinoButtonSize.small, + child: child, ))); final RenderBox buttonBox = tester.renderObject(find.byType(CupertinoButton)); expect( - buttonBox.size.width, - // 1 10px character + 64 * 2 = 138 for buttons with background. - 138.0, + buttonBox.size, + const Size(34.0, 28.0) + ); + + await tester.pumpWidget(boilerplate(child: const CupertinoButton( + onPressed: null, + sizeStyle: CupertinoButtonSize.medium, + child: child, + ))); + expect( + buttonBox.size, + const Size(40.0, 32.0), + ); + + await tester.pumpWidget(boilerplate(child: const CupertinoButton( + onPressed: null, + child: child, + ))); + expect( + buttonBox.size, + const Size(50.0, 44.0), ); }); @@ -404,8 +424,27 @@ void main() { ), ), ); + expect(textStyle.color, isSameColorAs(CupertinoColors.activeBlue)); + await tester.pumpWidget( + CupertinoApp( + home: CupertinoButton.tinted( + onPressed: () { }, + child: Builder(builder: (BuildContext context) { + textStyle = DefaultTextStyle.of(context).style; + return const Placeholder(); + }), + ), + ), + ); expect(textStyle.color, CupertinoColors.activeBlue); + BoxDecoration decoration = tester.widget( + find.descendant( + of: find.byType(CupertinoButton), + matching: find.byType(DecoratedBox), + ), + ).decoration as BoxDecoration; + expect(decoration.color, isSameColorAs(CupertinoColors.activeBlue.withOpacity(0.12))); await tester.pumpWidget( CupertinoApp( @@ -418,15 +457,14 @@ void main() { ), ), ); - expect(textStyle.color, isSameColorAs(CupertinoColors.white)); - BoxDecoration decoration = tester.widget( + decoration = tester.widget( find.descendant( of: find.byType(CupertinoButton), matching: find.byType(DecoratedBox), ), ).decoration as BoxDecoration; - expect(decoration.color, CupertinoColors.activeBlue); + expect(decoration.color, isSameColorAs(CupertinoColors.activeBlue)); await tester.pumpWidget( CupertinoApp( @@ -442,6 +480,27 @@ void main() { ); expect(textStyle.color, isSameColorAs(CupertinoColors.systemBlue.darkColor)); + await tester.pumpWidget( + CupertinoApp( + theme: const CupertinoThemeData(brightness: Brightness.dark), + home: CupertinoButton.tinted( + onPressed: () { }, + child: Builder(builder: (BuildContext context) { + textStyle = DefaultTextStyle.of(context).style; + return const Placeholder(); + }), + ), + ), + ); + expect(textStyle.color, isSameColorAs(CupertinoColors.systemBlue.darkColor)); + decoration = tester.widget( + find.descendant( + of: find.byType(CupertinoButton), + matching: find.byType(DecoratedBox), + ), + ).decoration as BoxDecoration; + expect(decoration.color, isSameColorAs(CupertinoColors.activeBlue.darkColor.withOpacity(0.26))); + await tester.pumpWidget( CupertinoApp( theme: const CupertinoThemeData(brightness: Brightness.dark), @@ -464,6 +523,14 @@ void main() { expect(decoration.color, isSameColorAs(CupertinoColors.systemBlue.darkColor)); }); + testWidgets("All CupertinoButton const maps keys' match the available style sizes", (WidgetTester tester) async { + for (final CupertinoButtonSize size in CupertinoButtonSize.values) { + expect(kCupertinoButtonPadding[size], isNotNull); + expect(kCupertinoButtonSizeBorderRadius[size], isNotNull); + expect(kCupertinoButtonMinSize[size], isNotNull); + } + }); + testWidgets('Hovering over Cupertino button updates cursor to clickable on Web', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( @@ -612,32 +679,57 @@ void main() { expect(focusNode.hasFocus, isFalse); }); - testWidgets('IconThemeData is not replaced by CupertinoButton', (WidgetTester tester) async { - const IconThemeData givenIconTheme = IconThemeData(size: 12.0); + testWidgets('IconThemeData falls back to default value when the TextStyle has a null size', (WidgetTester tester) async { + const IconThemeData defaultIconTheme = IconThemeData(size: kCupertinoButtonDefaultIconSize); IconThemeData? actualIconTheme; + // Large size. await tester.pumpWidget( CupertinoApp( + theme: const CupertinoThemeData( + textTheme: CupertinoTextThemeData( + actionTextStyle: TextStyle(), + ), + ), home: Center( - child: IconTheme( - data: givenIconTheme, - child: CupertinoButton( - onPressed: () {}, - child: Builder( - builder: (BuildContext context) { - actualIconTheme = IconTheme.of(context); + child: CupertinoButton( + onPressed: () {}, + child: Builder( + builder: (BuildContext context) { + actualIconTheme = IconTheme.of(context); - return const Placeholder(); - } - ), + return const Placeholder(); + } ), ), ), ), ); + expect(actualIconTheme?.size, defaultIconTheme.size); - expect(actualIconTheme?.size, givenIconTheme.size); + // Small size. + await tester.pumpWidget( + CupertinoApp( + theme: const CupertinoThemeData( + textTheme: CupertinoTextThemeData( + actionSmallTextStyle: TextStyle(), + ), + ), + home: Center( + child: CupertinoButton( + onPressed: () {}, + child: Builder( + builder: (BuildContext context) { + actualIconTheme = IconTheme.of(context); + + return const Placeholder(); + } + ), + ), + ), + ), + ); }); } diff --git a/packages/flutter/test/cupertino/text_theme_test.dart b/packages/flutter/test/cupertino/text_theme_test.dart index 7993d37441f..54ec5c84a15 100644 --- a/packages/flutter/test/cupertino/text_theme_test.dart +++ b/packages/flutter/test/cupertino/text_theme_test.dart @@ -29,6 +29,12 @@ void main() { expect(theme.actionTextStyle.letterSpacing, -0.41); expect(theme.actionTextStyle.fontWeight, null); + // ActionSmallTextStyle 15 -0.23 (aka "Subheadline/Regular") + expect(theme.actionSmallTextStyle.fontSize, 15); + expect(theme.actionSmallTextStyle.fontFamily, 'CupertinoSystemText'); + expect(theme.actionSmallTextStyle.letterSpacing, -0.23); + expect(theme.actionSmallTextStyle.fontWeight, null); + // TextStyle 17 -0.41 expect(theme.tabLabelTextStyle.fontSize, 10); expect(theme.tabLabelTextStyle.fontFamily, 'CupertinoSystemText'); diff --git a/packages/flutter/test/cupertino/theme_test.dart b/packages/flutter/test/cupertino/theme_test.dart index bc68425cad0..dd715c0fcb1 100644 --- a/packages/flutter/test/cupertino/theme_test.dart +++ b/packages/flutter/test/cupertino/theme_test.dart @@ -189,6 +189,7 @@ void main() { 'applyThemeToAll', 'textStyle', 'actionTextStyle', + 'actionSmallTextStyle', 'tabLabelTextStyle', 'navTitleTextStyle', 'navLargeTitleTextStyle',