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

This commit is contained in:
Rami 2021-07-27 10:21:04 -04:00 committed by GitHub
parent 738ce43d97
commit 83a215ed09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 18 deletions

View file

@ -171,6 +171,7 @@ class FloatingActionButton extends StatelessWidget {
_floatingActionButtonType = mini ? _FloatingActionButtonType.small : _FloatingActionButtonType.regular,
_extendedLabel = null,
extendedIconLabelSpacing = null,
extendedPadding = null,
super(key: key);
/// Creates a small circular floating action button.
@ -217,6 +218,7 @@ class FloatingActionButton extends StatelessWidget {
isExtended = false,
_extendedLabel = null,
extendedIconLabelSpacing = null,
extendedPadding = null,
super(key: key);
/// Creates a large circular floating action button.
@ -263,6 +265,7 @@ class FloatingActionButton extends StatelessWidget {
isExtended = false,
_extendedLabel = null,
extendedIconLabelSpacing = null,
extendedPadding = null,
super(key: key);
/// Creates a wider [StadiumBorder]-shaped floating action button with
@ -294,6 +297,7 @@ class FloatingActionButton extends StatelessWidget {
this.focusNode,
this.autofocus = false,
this.extendedIconLabelSpacing,
this.extendedPadding,
Widget? icon,
required Widget label,
this.enableFeedback,
@ -518,6 +522,14 @@ class FloatingActionButton extends StatelessWidget {
/// If that is also null, the default is 8.0.
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 Widget? _extendedLabel;
@ -596,16 +608,23 @@ class FloatingActionButton extends StatelessWidget {
case _FloatingActionButtonType.extended:
sizeConstraints = floatingActionButtonTheme.extendedSizeConstraints ?? _kExtendedSizeConstraints;
final double iconLabelSpacing = extendedIconLabelSpacing ?? floatingActionButtonTheme.extendedIconLabelSpacing ?? 8.0;
const Widget width20 = SizedBox(width: 20.0);
const Widget width16 = SizedBox(width: 16.0);
final EdgeInsetsGeometry padding = extendedPadding
?? floatingActionButtonTheme.extendedPadding
?? EdgeInsetsDirectional.only(start: child != null && isExtended ? 16.0 : 20.0, end: 20.0);
resolvedChild = _ChildOverflowBox(
child: Padding(
padding: padding,
child: Row(
mainAxisSize: MainAxisSize.min,
children: child == null
? <Widget>[width20, _extendedLabel!, width20]
: isExtended
? <Widget>[width16, child!, SizedBox(width: iconLabelSpacing), _extendedLabel!, width20]
: <Widget>[width20, child!, width20],
children: <Widget>[
if (child != null)
child!,
if (child != null && isExtended)
SizedBox(width: iconLabelSpacing),
if (isExtended)
_extendedLabel!,
],
),
),
);
break;

View file

@ -48,6 +48,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
this.largeSizeConstraints,
this.extendedSizeConstraints,
this.extendedIconLabelSpacing,
this.extendedPadding,
});
/// Color to be used for the unselected, enabled [FloatingActionButton]'s
@ -117,6 +118,9 @@ class FloatingActionButtonThemeData with Diagnosticable {
/// [FloatingActionButton].
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
/// new values.
FloatingActionButtonThemeData copyWith({
@ -137,6 +141,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
BoxConstraints? largeSizeConstraints,
BoxConstraints? extendedSizeConstraints,
double? extendedIconLabelSpacing,
EdgeInsetsGeometry? extendedPadding,
}) {
return FloatingActionButtonThemeData(
foregroundColor: foregroundColor ?? this.foregroundColor,
@ -156,6 +161,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
largeSizeConstraints: largeSizeConstraints ?? this.largeSizeConstraints,
extendedSizeConstraints: extendedSizeConstraints ?? this.extendedSizeConstraints,
extendedIconLabelSpacing: extendedIconLabelSpacing ?? this.extendedIconLabelSpacing,
extendedPadding: extendedPadding ?? this.extendedPadding,
);
}
@ -186,6 +192,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
largeSizeConstraints: BoxConstraints.lerp(a?.largeSizeConstraints, b?.largeSizeConstraints, t),
extendedSizeConstraints: BoxConstraints.lerp(a?.extendedSizeConstraints, b?.extendedSizeConstraints, t),
extendedIconLabelSpacing: lerpDouble(a?.extendedIconLabelSpacing, b?.extendedIconLabelSpacing, t),
extendedPadding: EdgeInsetsGeometry.lerp(a?.extendedPadding, b?.extendedPadding, t),
);
}
@ -209,6 +216,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
largeSizeConstraints,
extendedSizeConstraints,
extendedIconLabelSpacing,
extendedPadding,
);
}
@ -235,7 +243,8 @@ class FloatingActionButtonThemeData with Diagnosticable {
&& other.smallSizeConstraints == smallSizeConstraints
&& other.largeSizeConstraints == largeSizeConstraints
&& other.extendedSizeConstraints == extendedSizeConstraints
&& other.extendedIconLabelSpacing == extendedIconLabelSpacing;
&& other.extendedIconLabelSpacing == extendedIconLabelSpacing
&& other.extendedPadding == extendedPadding;
}
@override
@ -259,5 +268,6 @@ class FloatingActionButtonThemeData with Diagnosticable {
properties.add(DiagnosticsProperty<BoxConstraints>('largeSizeConstraints', largeSizeConstraints, defaultValue: null));
properties.add(DiagnosticsProperty<BoxConstraints>('extendedSizeConstraints', extendedSizeConstraints, defaultValue: null));
properties.add(DoubleProperty('extendedIconLabelSpacing', extendedIconLabelSpacing, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('extendedPadding', extendedPadding, defaultValue: null));
}
}

View file

@ -998,10 +998,11 @@ void main() {
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 labelKey = Key('label');
const double spacing = 33.0;
const EdgeInsetsDirectional padding = EdgeInsetsDirectional.only(start: 5.0, end: 6.0);
await tester.pumpWidget(
MaterialApp(
@ -1010,6 +1011,7 @@ void main() {
label: const Text('', key: labelKey),
icon: const Icon(Icons.add, key: iconKey),
extendedIconLabelSpacing: spacing,
extendedPadding: padding,
onPressed: () {},
),
),
@ -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(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', () {

View file

@ -180,13 +180,15 @@ void main() {
const Key iconKey = Key('icon');
const Key labelKey = Key('label');
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(
theme: ThemeData().copyWith(
floatingActionButtonTheme: const FloatingActionButtonThemeData(
extendedSizeConstraints: constraints,
extendedIconLabelSpacing: spacing,
extendedIconLabelSpacing: iconLabelSpacing,
extendedPadding: padding,
),
),
home: Scaffold(
@ -199,18 +201,22 @@ void main() {
));
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 {
const Key iconKey = Key('icon');
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(
theme: ThemeData().copyWith(
floatingActionButtonTheme: const FloatingActionButtonThemeData(
extendedIconLabelSpacing: 25.0,
extendedPadding: EdgeInsetsDirectional.only(start: 7.0, end: 8.0),
),
),
home: Scaffold(
@ -218,12 +224,15 @@ void main() {
onPressed: () { },
label: const Text('Extended', key: labelKey),
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 {
@ -258,6 +267,7 @@ void main() {
largeSizeConstraints: BoxConstraints.tightFor(width: 102.0, height: 102.0),
extendedSizeConstraints: BoxConstraints(minHeight: 103.0, maxHeight: 103.0),
extendedIconLabelSpacing: 12,
extendedPadding: EdgeInsetsDirectional.only(start: 7.0, end: 8.0),
).debugFillProperties(builder);
final List<String> description = builder.properties
@ -282,7 +292,8 @@ void main() {
'smallSizeConstraints: BoxConstraints(w=101.0, h=101.0)',
'largeSizeConstraints: BoxConstraints(w=102.0, h=102.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)',
]);
});
}