Unverified Commit 83a215ed authored by Rami's avatar Rami Committed by GitHub

Allow for customizing and theming of extended FAB content padding (#87062)

parent 738ce43d
...@@ -171,6 +171,7 @@ class FloatingActionButton extends StatelessWidget { ...@@ -171,6 +171,7 @@ class FloatingActionButton extends StatelessWidget {
_floatingActionButtonType = mini ? _FloatingActionButtonType.small : _FloatingActionButtonType.regular, _floatingActionButtonType = mini ? _FloatingActionButtonType.small : _FloatingActionButtonType.regular,
_extendedLabel = null, _extendedLabel = null,
extendedIconLabelSpacing = null, extendedIconLabelSpacing = null,
extendedPadding = null,
super(key: key); super(key: key);
/// Creates a small circular floating action button. /// Creates a small circular floating action button.
...@@ -217,6 +218,7 @@ class FloatingActionButton extends StatelessWidget { ...@@ -217,6 +218,7 @@ class FloatingActionButton extends StatelessWidget {
isExtended = false, isExtended = false,
_extendedLabel = null, _extendedLabel = null,
extendedIconLabelSpacing = null, extendedIconLabelSpacing = null,
extendedPadding = null,
super(key: key); super(key: key);
/// Creates a large circular floating action button. /// Creates a large circular floating action button.
...@@ -263,6 +265,7 @@ class FloatingActionButton extends StatelessWidget { ...@@ -263,6 +265,7 @@ class FloatingActionButton extends StatelessWidget {
isExtended = false, isExtended = false,
_extendedLabel = null, _extendedLabel = null,
extendedIconLabelSpacing = null, extendedIconLabelSpacing = null,
extendedPadding = null,
super(key: key); super(key: key);
/// Creates a wider [StadiumBorder]-shaped floating action button with /// Creates a wider [StadiumBorder]-shaped floating action button with
...@@ -294,6 +297,7 @@ class FloatingActionButton extends StatelessWidget { ...@@ -294,6 +297,7 @@ class FloatingActionButton extends StatelessWidget {
this.focusNode, this.focusNode,
this.autofocus = false, this.autofocus = false,
this.extendedIconLabelSpacing, this.extendedIconLabelSpacing,
this.extendedPadding,
Widget? icon, Widget? icon,
required Widget label, required Widget label,
this.enableFeedback, this.enableFeedback,
...@@ -518,6 +522,14 @@ class FloatingActionButton extends StatelessWidget { ...@@ -518,6 +522,14 @@ class FloatingActionButton extends StatelessWidget {
/// If that is also null, the default is 8.0. /// If that is also null, the default is 8.0.
final double? extendedIconLabelSpacing; final double? extendedIconLabelSpacing;
/// The padding for an extended [FloatingActionButton]'s content.
///
/// If null, [FloatingActionButtonThemeData.extendedPadding] is used. If that
/// is also null, the default is
/// `EdgeInsetsDirectional.only(start: 16.0, end: 20.0)` if an icon is
/// provided, and `EdgeInsetsDirectional.only(start: 20.0, end: 20.0)` if not.
final EdgeInsetsGeometry? extendedPadding;
final _FloatingActionButtonType _floatingActionButtonType; final _FloatingActionButtonType _floatingActionButtonType;
final Widget? _extendedLabel; final Widget? _extendedLabel;
...@@ -596,16 +608,23 @@ class FloatingActionButton extends StatelessWidget { ...@@ -596,16 +608,23 @@ class FloatingActionButton extends StatelessWidget {
case _FloatingActionButtonType.extended: case _FloatingActionButtonType.extended:
sizeConstraints = floatingActionButtonTheme.extendedSizeConstraints ?? _kExtendedSizeConstraints; sizeConstraints = floatingActionButtonTheme.extendedSizeConstraints ?? _kExtendedSizeConstraints;
final double iconLabelSpacing = extendedIconLabelSpacing ?? floatingActionButtonTheme.extendedIconLabelSpacing ?? 8.0; final double iconLabelSpacing = extendedIconLabelSpacing ?? floatingActionButtonTheme.extendedIconLabelSpacing ?? 8.0;
const Widget width20 = SizedBox(width: 20.0); final EdgeInsetsGeometry padding = extendedPadding
const Widget width16 = SizedBox(width: 16.0); ?? floatingActionButtonTheme.extendedPadding
?? EdgeInsetsDirectional.only(start: child != null && isExtended ? 16.0 : 20.0, end: 20.0);
resolvedChild = _ChildOverflowBox( resolvedChild = _ChildOverflowBox(
child: Row( child: Padding(
mainAxisSize: MainAxisSize.min, padding: padding,
children: child == null child: Row(
? <Widget>[width20, _extendedLabel!, width20] mainAxisSize: MainAxisSize.min,
: isExtended children: <Widget>[
? <Widget>[width16, child!, SizedBox(width: iconLabelSpacing), _extendedLabel!, width20] if (child != null)
: <Widget>[width20, child!, width20], child!,
if (child != null && isExtended)
SizedBox(width: iconLabelSpacing),
if (isExtended)
_extendedLabel!,
],
),
), ),
); );
break; break;
......
...@@ -48,6 +48,7 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -48,6 +48,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
this.largeSizeConstraints, this.largeSizeConstraints,
this.extendedSizeConstraints, this.extendedSizeConstraints,
this.extendedIconLabelSpacing, this.extendedIconLabelSpacing,
this.extendedPadding,
}); });
/// Color to be used for the unselected, enabled [FloatingActionButton]'s /// Color to be used for the unselected, enabled [FloatingActionButton]'s
...@@ -117,6 +118,9 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -117,6 +118,9 @@ class FloatingActionButtonThemeData with Diagnosticable {
/// [FloatingActionButton]. /// [FloatingActionButton].
final double? extendedIconLabelSpacing; final double? extendedIconLabelSpacing;
/// The padding for an extended [FloatingActionButton]'s content.
final EdgeInsetsGeometry? extendedPadding;
/// Creates a copy of this object with the given fields replaced with the /// Creates a copy of this object with the given fields replaced with the
/// new values. /// new values.
FloatingActionButtonThemeData copyWith({ FloatingActionButtonThemeData copyWith({
...@@ -137,6 +141,7 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -137,6 +141,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
BoxConstraints? largeSizeConstraints, BoxConstraints? largeSizeConstraints,
BoxConstraints? extendedSizeConstraints, BoxConstraints? extendedSizeConstraints,
double? extendedIconLabelSpacing, double? extendedIconLabelSpacing,
EdgeInsetsGeometry? extendedPadding,
}) { }) {
return FloatingActionButtonThemeData( return FloatingActionButtonThemeData(
foregroundColor: foregroundColor ?? this.foregroundColor, foregroundColor: foregroundColor ?? this.foregroundColor,
...@@ -156,6 +161,7 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -156,6 +161,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
largeSizeConstraints: largeSizeConstraints ?? this.largeSizeConstraints, largeSizeConstraints: largeSizeConstraints ?? this.largeSizeConstraints,
extendedSizeConstraints: extendedSizeConstraints ?? this.extendedSizeConstraints, extendedSizeConstraints: extendedSizeConstraints ?? this.extendedSizeConstraints,
extendedIconLabelSpacing: extendedIconLabelSpacing ?? this.extendedIconLabelSpacing, extendedIconLabelSpacing: extendedIconLabelSpacing ?? this.extendedIconLabelSpacing,
extendedPadding: extendedPadding ?? this.extendedPadding,
); );
} }
...@@ -186,6 +192,7 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -186,6 +192,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
largeSizeConstraints: BoxConstraints.lerp(a?.largeSizeConstraints, b?.largeSizeConstraints, t), largeSizeConstraints: BoxConstraints.lerp(a?.largeSizeConstraints, b?.largeSizeConstraints, t),
extendedSizeConstraints: BoxConstraints.lerp(a?.extendedSizeConstraints, b?.extendedSizeConstraints, t), extendedSizeConstraints: BoxConstraints.lerp(a?.extendedSizeConstraints, b?.extendedSizeConstraints, t),
extendedIconLabelSpacing: lerpDouble(a?.extendedIconLabelSpacing, b?.extendedIconLabelSpacing, t), extendedIconLabelSpacing: lerpDouble(a?.extendedIconLabelSpacing, b?.extendedIconLabelSpacing, t),
extendedPadding: EdgeInsetsGeometry.lerp(a?.extendedPadding, b?.extendedPadding, t),
); );
} }
...@@ -209,6 +216,7 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -209,6 +216,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
largeSizeConstraints, largeSizeConstraints,
extendedSizeConstraints, extendedSizeConstraints,
extendedIconLabelSpacing, extendedIconLabelSpacing,
extendedPadding,
); );
} }
...@@ -235,7 +243,8 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -235,7 +243,8 @@ class FloatingActionButtonThemeData with Diagnosticable {
&& other.smallSizeConstraints == smallSizeConstraints && other.smallSizeConstraints == smallSizeConstraints
&& other.largeSizeConstraints == largeSizeConstraints && other.largeSizeConstraints == largeSizeConstraints
&& other.extendedSizeConstraints == extendedSizeConstraints && other.extendedSizeConstraints == extendedSizeConstraints
&& other.extendedIconLabelSpacing == extendedIconLabelSpacing; && other.extendedIconLabelSpacing == extendedIconLabelSpacing
&& other.extendedPadding == extendedPadding;
} }
@override @override
...@@ -259,5 +268,6 @@ class FloatingActionButtonThemeData with Diagnosticable { ...@@ -259,5 +268,6 @@ class FloatingActionButtonThemeData with Diagnosticable {
properties.add(DiagnosticsProperty<BoxConstraints>('largeSizeConstraints', largeSizeConstraints, defaultValue: null)); properties.add(DiagnosticsProperty<BoxConstraints>('largeSizeConstraints', largeSizeConstraints, defaultValue: null));
properties.add(DiagnosticsProperty<BoxConstraints>('extendedSizeConstraints', extendedSizeConstraints, defaultValue: null)); properties.add(DiagnosticsProperty<BoxConstraints>('extendedSizeConstraints', extendedSizeConstraints, defaultValue: null));
properties.add(DoubleProperty('extendedIconLabelSpacing', extendedIconLabelSpacing, defaultValue: null)); properties.add(DoubleProperty('extendedIconLabelSpacing', extendedIconLabelSpacing, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('extendedPadding', extendedPadding, defaultValue: null));
} }
} }
...@@ -998,10 +998,11 @@ void main() { ...@@ -998,10 +998,11 @@ void main() {
expect(tester.getSize(find.byKey(key)), const Size(96.0, 96.0)); expect(tester.getSize(find.byKey(key)), const Size(96.0, 96.0));
}); });
testWidgets('FloatingActionButton.extended can customize spacing between icon and label', (WidgetTester tester) async { testWidgets('FloatingActionButton.extended can customize spacing', (WidgetTester tester) async {
const Key iconKey = Key('icon'); const Key iconKey = Key('icon');
const Key labelKey = Key('label'); const Key labelKey = Key('label');
const double spacing = 33.0; const double spacing = 33.0;
const EdgeInsetsDirectional padding = EdgeInsetsDirectional.only(start: 5.0, end: 6.0);
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
...@@ -1010,6 +1011,7 @@ void main() { ...@@ -1010,6 +1011,7 @@ void main() {
label: const Text('', key: labelKey), label: const Text('', key: labelKey),
icon: const Icon(Icons.add, key: iconKey), icon: const Icon(Icons.add, key: iconKey),
extendedIconLabelSpacing: spacing, extendedIconLabelSpacing: spacing,
extendedPadding: padding,
onPressed: () {}, onPressed: () {},
), ),
), ),
...@@ -1017,6 +1019,8 @@ void main() { ...@@ -1017,6 +1019,8 @@ void main() {
); );
expect(tester.getTopLeft(find.byKey(labelKey)).dx - tester.getTopRight(find.byKey(iconKey)).dx, spacing); expect(tester.getTopLeft(find.byKey(labelKey)).dx - tester.getTopRight(find.byKey(iconKey)).dx, spacing);
expect(tester.getTopLeft(find.byKey(iconKey)).dx - tester.getTopLeft(find.byType(FloatingActionButton)).dx, padding.start);
expect(tester.getTopRight(find.byType(FloatingActionButton)).dx - tester.getTopRight(find.byKey(labelKey)).dx, padding.end);
}); });
group('feedback', () { group('feedback', () {
......
...@@ -180,13 +180,15 @@ void main() { ...@@ -180,13 +180,15 @@ void main() {
const Key iconKey = Key('icon'); const Key iconKey = Key('icon');
const Key labelKey = Key('label'); const Key labelKey = Key('label');
const BoxConstraints constraints = BoxConstraints.tightFor(height: 100.0); const BoxConstraints constraints = BoxConstraints.tightFor(height: 100.0);
const double spacing = 33.0; const double iconLabelSpacing = 33.0;
const EdgeInsetsDirectional padding = EdgeInsetsDirectional.only(start: 5.0, end: 6.0);
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData().copyWith( theme: ThemeData().copyWith(
floatingActionButtonTheme: const FloatingActionButtonThemeData( floatingActionButtonTheme: const FloatingActionButtonThemeData(
extendedSizeConstraints: constraints, extendedSizeConstraints: constraints,
extendedIconLabelSpacing: spacing, extendedIconLabelSpacing: iconLabelSpacing,
extendedPadding: padding,
), ),
), ),
home: Scaffold( home: Scaffold(
...@@ -199,18 +201,22 @@ void main() { ...@@ -199,18 +201,22 @@ void main() {
)); ));
expect(_getRawMaterialButton(tester).constraints, constraints); expect(_getRawMaterialButton(tester).constraints, constraints);
expect(tester.getTopLeft(find.byKey(labelKey)).dx - tester.getTopRight(find.byKey(iconKey)).dx, spacing); expect(tester.getTopLeft(find.byKey(labelKey)).dx - tester.getTopRight(find.byKey(iconKey)).dx, iconLabelSpacing);
expect(tester.getTopLeft(find.byKey(iconKey)).dx - tester.getTopLeft(find.byType(FloatingActionButton)).dx, padding.start);
expect(tester.getTopRight(find.byType(FloatingActionButton)).dx - tester.getTopRight(find.byKey(labelKey)).dx, padding.end);
}); });
testWidgets('FloatingActionButton.extended spacing takes priority over FloatingActionButtonThemeData spacing', (WidgetTester tester) async { testWidgets('FloatingActionButton.extended spacing takes priority over FloatingActionButtonThemeData spacing', (WidgetTester tester) async {
const Key iconKey = Key('icon'); const Key iconKey = Key('icon');
const Key labelKey = Key('label'); const Key labelKey = Key('label');
const double spacing = 33.0; const double iconLabelSpacing = 33.0;
const EdgeInsetsDirectional padding = EdgeInsetsDirectional.only(start: 5.0, end: 6.0);
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData().copyWith( theme: ThemeData().copyWith(
floatingActionButtonTheme: const FloatingActionButtonThemeData( floatingActionButtonTheme: const FloatingActionButtonThemeData(
extendedIconLabelSpacing: 25.0, extendedIconLabelSpacing: 25.0,
extendedPadding: EdgeInsetsDirectional.only(start: 7.0, end: 8.0),
), ),
), ),
home: Scaffold( home: Scaffold(
...@@ -218,12 +224,15 @@ void main() { ...@@ -218,12 +224,15 @@ void main() {
onPressed: () { }, onPressed: () { },
label: const Text('Extended', key: labelKey), label: const Text('Extended', key: labelKey),
icon: const Icon(Icons.add, key: iconKey), icon: const Icon(Icons.add, key: iconKey),
extendedIconLabelSpacing: spacing, extendedIconLabelSpacing: iconLabelSpacing,
extendedPadding: padding,
), ),
), ),
)); ));
expect(tester.getTopLeft(find.byKey(labelKey)).dx - tester.getTopRight(find.byKey(iconKey)).dx, spacing); expect(tester.getTopLeft(find.byKey(labelKey)).dx - tester.getTopRight(find.byKey(iconKey)).dx, iconLabelSpacing);
expect(tester.getTopLeft(find.byKey(iconKey)).dx - tester.getTopLeft(find.byType(FloatingActionButton)).dx, padding.start);
expect(tester.getTopRight(find.byType(FloatingActionButton)).dx - tester.getTopRight(find.byKey(labelKey)).dx, padding.end);
}); });
testWidgets('default FloatingActionButton debugFillProperties', (WidgetTester tester) async { testWidgets('default FloatingActionButton debugFillProperties', (WidgetTester tester) async {
...@@ -258,6 +267,7 @@ void main() { ...@@ -258,6 +267,7 @@ void main() {
largeSizeConstraints: BoxConstraints.tightFor(width: 102.0, height: 102.0), largeSizeConstraints: BoxConstraints.tightFor(width: 102.0, height: 102.0),
extendedSizeConstraints: BoxConstraints(minHeight: 103.0, maxHeight: 103.0), extendedSizeConstraints: BoxConstraints(minHeight: 103.0, maxHeight: 103.0),
extendedIconLabelSpacing: 12, extendedIconLabelSpacing: 12,
extendedPadding: EdgeInsetsDirectional.only(start: 7.0, end: 8.0),
).debugFillProperties(builder); ).debugFillProperties(builder);
final List<String> description = builder.properties final List<String> description = builder.properties
...@@ -282,7 +292,8 @@ void main() { ...@@ -282,7 +292,8 @@ void main() {
'smallSizeConstraints: BoxConstraints(w=101.0, h=101.0)', 'smallSizeConstraints: BoxConstraints(w=101.0, h=101.0)',
'largeSizeConstraints: BoxConstraints(w=102.0, h=102.0)', 'largeSizeConstraints: BoxConstraints(w=102.0, h=102.0)',
'extendedSizeConstraints: BoxConstraints(0.0<=w<=Infinity, h=103.0)', 'extendedSizeConstraints: BoxConstraints(0.0<=w<=Infinity, h=103.0)',
'extendedIconLabelSpacing: 12.0' 'extendedIconLabelSpacing: 12.0',
'extendedPadding: EdgeInsetsDirectional(7.0, 0.0, 8.0, 0.0)',
]); ]);
}); });
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment