Skip to content

Commit 2ab2ca2

Browse files
authored
Migrate FloatingActionButton to Material 3 (#94486)
1 parent 20ff180 commit 2ab2ca2

File tree

6 files changed

+536
-74
lines changed

6 files changed

+536
-74
lines changed

dev/tools/gen_defaults/data/material-tokens.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"version": "v0.72",
3-
"date": "2021-12-16 00:27:25.239571",
2+
"version": "v0.74",
3+
"date": "2022-01-06",
44
"md.sys.color.light.on-tertiary": "md.ref.palette.tertiary100",
55
"md.sys.color.light.on-secondary-container": "md.ref.palette.secondary10",
66
"md.sys.color.light.on-secondary": "md.ref.palette.secondary100",

packages/flutter/lib/src/material/floating_action_button.dart

Lines changed: 176 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,14 @@ import 'package:flutter/rendering.dart';
99
import 'package:flutter/widgets.dart';
1010

1111
import 'button.dart';
12+
import 'color_scheme.dart';
1213
import 'floating_action_button_theme.dart';
1314
import 'scaffold.dart';
15+
import 'text_theme.dart';
1416
import 'theme.dart';
1517
import 'theme_data.dart';
1618
import 'tooltip.dart';
1719

18-
const BoxConstraints _kSizeConstraints = BoxConstraints.tightFor(
19-
width: 56.0,
20-
height: 56.0,
21-
);
22-
23-
const BoxConstraints _kMiniSizeConstraints = BoxConstraints.tightFor(
24-
width: 40.0,
25-
height: 40.0,
26-
);
27-
28-
const BoxConstraints _kLargeSizeConstraints = BoxConstraints.tightFor(
29-
width: 96.0,
30-
height: 96.0,
31-
);
32-
33-
const BoxConstraints _kExtendedSizeConstraints = BoxConstraints.tightFor(
34-
height: 48.0,
35-
);
36-
3720
class _DefaultHeroTag {
3821
const _DefaultHeroTag();
3922
@override
@@ -508,82 +491,80 @@ class FloatingActionButton extends StatelessWidget {
508491

509492
final Widget? _extendedLabel;
510493

511-
static const double _defaultElevation = 6;
512-
static const double _defaultFocusElevation = 6;
513-
static const double _defaultHoverElevation = 8;
514-
static const double _defaultHighlightElevation = 12;
515-
static const ShapeBorder _defaultShape = CircleBorder();
516-
static const ShapeBorder _defaultExtendedShape = StadiumBorder();
517-
518494
@override
519495
Widget build(BuildContext context) {
520496
final ThemeData theme = Theme.of(context);
521497
final FloatingActionButtonThemeData floatingActionButtonTheme = theme.floatingActionButtonTheme;
498+
final FloatingActionButtonThemeData defaults = theme.useMaterial3
499+
? _M3Defaults(context, _floatingActionButtonType, child != null)
500+
: _M2Defaults(context, _floatingActionButtonType, child != null);
522501

523502
final Color foregroundColor = this.foregroundColor
524503
?? floatingActionButtonTheme.foregroundColor
525-
?? theme.colorScheme.onSecondary;
504+
?? defaults.foregroundColor!;
526505
final Color backgroundColor = this.backgroundColor
527506
?? floatingActionButtonTheme.backgroundColor
528-
?? theme.colorScheme.secondary;
507+
?? defaults.backgroundColor!;
529508
final Color focusColor = this.focusColor
530509
?? floatingActionButtonTheme.focusColor
531-
?? theme.focusColor;
510+
?? defaults.focusColor!;
532511
final Color hoverColor = this.hoverColor
533512
?? floatingActionButtonTheme.hoverColor
534-
?? theme.hoverColor;
513+
?? defaults.hoverColor!;
535514
final Color splashColor = this.splashColor
536515
?? floatingActionButtonTheme.splashColor
537-
?? theme.splashColor;
516+
?? defaults.splashColor!;
538517
final double elevation = this.elevation
539518
?? floatingActionButtonTheme.elevation
540-
?? _defaultElevation;
519+
?? defaults.elevation!;
541520
final double focusElevation = this.focusElevation
542521
?? floatingActionButtonTheme.focusElevation
543-
?? _defaultFocusElevation;
522+
?? defaults.focusElevation!;
544523
final double hoverElevation = this.hoverElevation
545524
?? floatingActionButtonTheme.hoverElevation
546-
?? _defaultHoverElevation;
525+
?? defaults.hoverElevation!;
547526
final double disabledElevation = this.disabledElevation
548527
?? floatingActionButtonTheme.disabledElevation
528+
?? defaults.disabledElevation
549529
?? elevation;
550530
final double highlightElevation = this.highlightElevation
551531
?? floatingActionButtonTheme.highlightElevation
552-
?? _defaultHighlightElevation;
532+
?? defaults.highlightElevation!;
553533
final MaterialTapTargetSize materialTapTargetSize = this.materialTapTargetSize
554534
?? theme.materialTapTargetSize;
555535
final bool enableFeedback = this.enableFeedback
556-
?? floatingActionButtonTheme.enableFeedback ?? true;
536+
?? floatingActionButtonTheme.enableFeedback
537+
?? defaults.enableFeedback!;
538+
final double iconSize = floatingActionButtonTheme.iconSize
539+
?? defaults.iconSize!;
557540
final TextStyle extendedTextStyle = (this.extendedTextStyle
558-
?? floatingActionButtonTheme.extendedTextStyle
559-
?? theme.textTheme.button!.copyWith(letterSpacing: 1.2)).copyWith(color: foregroundColor);
541+
?? floatingActionButtonTheme.extendedTextStyle
542+
?? defaults.extendedTextStyle!).copyWith(color: foregroundColor);
560543
final ShapeBorder shape = this.shape
561544
?? floatingActionButtonTheme.shape
562-
?? (isExtended ? _defaultExtendedShape : _defaultShape);
545+
?? defaults.shape!;
563546

564547
BoxConstraints sizeConstraints;
565-
Widget? resolvedChild = child;
548+
Widget? resolvedChild = child != null ? IconTheme.merge(
549+
data: IconThemeData(size: iconSize),
550+
child: child!,
551+
) : child;
566552
switch(_floatingActionButtonType) {
567553
case _FloatingActionButtonType.regular:
568-
sizeConstraints = floatingActionButtonTheme.sizeConstraints ?? _kSizeConstraints;
554+
sizeConstraints = floatingActionButtonTheme.sizeConstraints ?? defaults.sizeConstraints!;
569555
break;
570556
case _FloatingActionButtonType.small:
571-
sizeConstraints = floatingActionButtonTheme.smallSizeConstraints ?? _kMiniSizeConstraints;
557+
sizeConstraints = floatingActionButtonTheme.smallSizeConstraints ?? defaults.smallSizeConstraints!;
572558
break;
573559
case _FloatingActionButtonType.large:
574-
sizeConstraints = floatingActionButtonTheme.largeSizeConstraints ?? _kLargeSizeConstraints;
575-
// The large FAB uses a larger icon.
576-
resolvedChild = child != null ? IconTheme.merge(
577-
data: const IconThemeData(size: 36.0),
578-
child: child!,
579-
) : child;
560+
sizeConstraints = floatingActionButtonTheme.largeSizeConstraints ?? defaults.largeSizeConstraints!;
580561
break;
581562
case _FloatingActionButtonType.extended:
582-
sizeConstraints = floatingActionButtonTheme.extendedSizeConstraints ?? _kExtendedSizeConstraints;
563+
sizeConstraints = floatingActionButtonTheme.extendedSizeConstraints ?? defaults.extendedSizeConstraints!;
583564
final double iconLabelSpacing = extendedIconLabelSpacing ?? floatingActionButtonTheme.extendedIconLabelSpacing ?? 8.0;
584565
final EdgeInsetsGeometry padding = extendedPadding
585566
?? floatingActionButtonTheme.extendedPadding
586-
?? EdgeInsetsDirectional.only(start: child != null && isExtended ? 16.0 : 20.0, end: 20.0);
567+
?? defaults.extendedPadding!;
587568
resolvedChild = _ChildOverflowBox(
588569
child: Padding(
589570
padding: padding,
@@ -730,3 +711,148 @@ class _RenderChildOverflowBox extends RenderAligningShiftedBox {
730711
}
731712
}
732713
}
714+
715+
// Generate a FloatingActionButtonThemeData that represents
716+
// the M2 default values. This was generated by hand from the
717+
// previous hand coded defaults for M2. It uses get method overrides
718+
// instead of properties to avoid computing values that we may not
719+
// need upfront.
720+
class _M2Defaults extends FloatingActionButtonThemeData {
721+
_M2Defaults(BuildContext context, this.type, this.hasChild)
722+
: _theme = Theme.of(context),
723+
_colors = Theme.of(context).colorScheme;
724+
725+
final _FloatingActionButtonType type;
726+
final bool hasChild;
727+
final ThemeData _theme;
728+
final ColorScheme _colors;
729+
730+
bool get _isExtended => type == _FloatingActionButtonType.extended;
731+
bool get _isLarge => type == _FloatingActionButtonType.large;
732+
733+
@override Color? get foregroundColor => _colors.onSecondary;
734+
@override Color? get backgroundColor => _colors.secondary;
735+
@override Color? get focusColor => _theme.focusColor;
736+
@override Color? get hoverColor => _theme.hoverColor;
737+
@override Color? get splashColor => _theme.splashColor;
738+
@override double? get elevation => 6;
739+
@override double? get focusElevation => 6;
740+
@override double? get hoverElevation => 8;
741+
@override double? get highlightElevation => 12;
742+
@override ShapeBorder? get shape => _isExtended ? const StadiumBorder() : const CircleBorder();
743+
@override bool? get enableFeedback => true;
744+
@override double? get iconSize => _isLarge ? 36.0 : 24.0;
745+
746+
@override
747+
BoxConstraints? get sizeConstraints => const BoxConstraints.tightFor(
748+
width: 56.0,
749+
height: 56.0,
750+
);
751+
752+
@override
753+
BoxConstraints? get smallSizeConstraints => const BoxConstraints.tightFor(
754+
width: 40.0,
755+
height: 40.0,
756+
);
757+
758+
@override
759+
BoxConstraints? get largeSizeConstraints => const BoxConstraints.tightFor(
760+
width: 96.0,
761+
height: 96.0,
762+
);
763+
764+
@override
765+
BoxConstraints? get extendedSizeConstraints => const BoxConstraints.tightFor(
766+
height: 48.0,
767+
);
768+
769+
@override double? get extendedIconLabelSpacing => 8.0;
770+
@override EdgeInsetsGeometry? get extendedPadding => EdgeInsetsDirectional.only(start: hasChild && _isExtended ? 16.0 : 20.0, end: 20.0);
771+
@override TextStyle? get extendedTextStyle => _theme.textTheme.button!.copyWith(letterSpacing: 1.2);
772+
}
773+
774+
// BEGIN GENERATED TOKEN PROPERTIES
775+
776+
// Generated code to the end of this file. Do not edit by hand.
777+
// These defaults are generated from the Material Design Token
778+
// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart.
779+
780+
// Generated version v0.74, 2022-01-06
781+
class _M3Defaults extends FloatingActionButtonThemeData {
782+
_M3Defaults(this.context, this.type, this.hasChild)
783+
: _colors = Theme.of(context).colorScheme,
784+
_textTheme = Theme.of(context).textTheme;
785+
786+
final BuildContext context;
787+
final _FloatingActionButtonType type;
788+
final bool hasChild;
789+
final ColorScheme _colors;
790+
final TextTheme _textTheme;
791+
792+
bool get _isExtended => type == _FloatingActionButtonType.extended;
793+
794+
@override Color? get foregroundColor => _colors.onPrimaryContainer;
795+
@override Color? get backgroundColor => _colors.primaryContainer;
796+
@override Color? get splashColor => _colors.onPrimaryContainer.withOpacity(0.12);
797+
@override double get elevation => 6.0;
798+
@override Color? get focusColor => _colors.onPrimaryContainer.withOpacity(0.12);
799+
@override double get focusElevation => 6.0;
800+
@override Color? get hoverColor => _colors.onPrimaryContainer.withOpacity(0.08);
801+
@override double get hoverElevation => 8.0;
802+
@override double get highlightElevation => 6.0;
803+
804+
@override
805+
ShapeBorder? get shape {
806+
switch (type) {
807+
case _FloatingActionButtonType.regular:
808+
return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)));
809+
case _FloatingActionButtonType.small:
810+
return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12.0)));
811+
case _FloatingActionButtonType.large:
812+
return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0)));
813+
case _FloatingActionButtonType.extended:
814+
return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)));
815+
}
816+
}
817+
818+
@override bool? get enableFeedback => true;
819+
820+
@override
821+
double? get iconSize {
822+
switch (type) {
823+
case _FloatingActionButtonType.regular: return 24.0;
824+
case _FloatingActionButtonType.small: return 24.0;
825+
case _FloatingActionButtonType.large: return 36.0;
826+
case _FloatingActionButtonType.extended: return 24.0;
827+
}
828+
}
829+
830+
@override
831+
BoxConstraints? get sizeConstraints => const BoxConstraints.tightFor(
832+
width: 56.0,
833+
height: 56.0,
834+
);
835+
836+
@override
837+
BoxConstraints? get smallSizeConstraints => const BoxConstraints.tightFor(
838+
width: 40.0,
839+
height: 40.0,
840+
);
841+
842+
@override
843+
BoxConstraints? get largeSizeConstraints => const BoxConstraints.tightFor(
844+
width: 96.0,
845+
height: 96.0,
846+
);
847+
848+
@override
849+
BoxConstraints? get extendedSizeConstraints => const BoxConstraints.tightFor(
850+
height: 56.0,
851+
);
852+
853+
@override double? get extendedIconLabelSpacing => 8.0;
854+
@override EdgeInsetsGeometry? get extendedPadding => EdgeInsetsDirectional.only(start: hasChild && _isExtended ? 16.0 : 20.0, end: 20.0);
855+
@override TextStyle? get extendedTextStyle => _textTheme.labelLarge;
856+
}
857+
858+
// END GENERATED TOKEN PROPERTIES

packages/flutter/lib/src/material/floating_action_button_theme.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
4343
this.highlightElevation,
4444
this.shape,
4545
this.enableFeedback,
46+
this.iconSize,
4647
this.sizeConstraints,
4748
this.smallSizeConstraints,
4849
this.largeSizeConstraints,
@@ -103,6 +104,9 @@ class FloatingActionButtonThemeData with Diagnosticable {
103104
/// ignored.
104105
final bool? enableFeedback;
105106

107+
/// Overrides the default icon size for the [FloatingActionButton];
108+
final double? iconSize;
109+
106110
/// Overrides the default size constraints for the [FloatingActionButton].
107111
final BoxConstraints? sizeConstraints;
108112

@@ -140,6 +144,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
140144
double? highlightElevation,
141145
ShapeBorder? shape,
142146
bool? enableFeedback,
147+
double? iconSize,
143148
BoxConstraints? sizeConstraints,
144149
BoxConstraints? smallSizeConstraints,
145150
BoxConstraints? largeSizeConstraints,
@@ -161,6 +166,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
161166
highlightElevation: highlightElevation ?? this.highlightElevation,
162167
shape: shape ?? this.shape,
163168
enableFeedback: enableFeedback ?? this.enableFeedback,
169+
iconSize: iconSize ?? this.iconSize,
164170
sizeConstraints: sizeConstraints ?? this.sizeConstraints,
165171
smallSizeConstraints: smallSizeConstraints ?? this.smallSizeConstraints,
166172
largeSizeConstraints: largeSizeConstraints ?? this.largeSizeConstraints,
@@ -193,6 +199,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
193199
highlightElevation: lerpDouble(a?.highlightElevation, b?.highlightElevation, t),
194200
shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
195201
enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback,
202+
iconSize: lerpDouble(a?.iconSize, b?.iconSize, t),
196203
sizeConstraints: BoxConstraints.lerp(a?.sizeConstraints, b?.sizeConstraints, t),
197204
smallSizeConstraints: BoxConstraints.lerp(a?.smallSizeConstraints, b?.smallSizeConstraints, t),
198205
largeSizeConstraints: BoxConstraints.lerp(a?.largeSizeConstraints, b?.largeSizeConstraints, t),
@@ -218,6 +225,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
218225
highlightElevation,
219226
shape,
220227
enableFeedback,
228+
iconSize,
221229
sizeConstraints,
222230
smallSizeConstraints,
223231
largeSizeConstraints,
@@ -247,6 +255,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
247255
&& other.highlightElevation == highlightElevation
248256
&& other.shape == shape
249257
&& other.enableFeedback == enableFeedback
258+
&& other.iconSize == iconSize
250259
&& other.sizeConstraints == sizeConstraints
251260
&& other.smallSizeConstraints == smallSizeConstraints
252261
&& other.largeSizeConstraints == largeSizeConstraints
@@ -272,6 +281,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
272281
properties.add(DoubleProperty('highlightElevation', highlightElevation, defaultValue: null));
273282
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
274283
properties.add(DiagnosticsProperty<bool>('enableFeedback', enableFeedback, defaultValue: null));
284+
properties.add(DoubleProperty('iconSize', iconSize, defaultValue: null));
275285
properties.add(DiagnosticsProperty<BoxConstraints>('sizeConstraints', sizeConstraints, defaultValue: null));
276286
properties.add(DiagnosticsProperty<BoxConstraints>('smallSizeConstraints', smallSizeConstraints, defaultValue: null));
277287
properties.add(DiagnosticsProperty<BoxConstraints>('largeSizeConstraints', largeSizeConstraints, defaultValue: null));

packages/flutter/lib/src/material/theme_data.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,10 +1134,6 @@ class ThemeData with Diagnosticable {
11341134
/// start using new colors, typography and other features of Material 3.
11351135
/// If false, they will use the Material 2 look and feel.
11361136
///
1137-
/// Currently no components have been migrated to support Material 3.
1138-
/// As they are updated to include Material 3 support this documentation
1139-
/// will be modified to indicate exactly what widgets this flag will affect.
1140-
///
11411137
/// During the migration to Material 3, turning this on may yield
11421138
/// inconsistent look and feel in your app. Some components will be migrated
11431139
/// before others and typography changes will be coming in stages.
@@ -1148,6 +1144,10 @@ class ThemeData with Diagnosticable {
11481144
/// all uses of it. Everything will use the Material 3 look and feel at
11491145
/// that point.
11501146
///
1147+
/// Components that have been migrated to Material 3 are:
1148+
///
1149+
/// * [FloatingActionButton]
1150+
///
11511151
/// See also:
11521152
///
11531153
/// * [Material Design 3](https://m3.material.io/).

0 commit comments

Comments
 (0)