Allow for customizing and theming extended FAB's TextStyle (#87498)
This commit is contained in:
parent
22436cca0e
commit
37c414dd8e
@ -172,6 +172,7 @@ class FloatingActionButton extends StatelessWidget {
|
|||||||
_extendedLabel = null,
|
_extendedLabel = null,
|
||||||
extendedIconLabelSpacing = null,
|
extendedIconLabelSpacing = null,
|
||||||
extendedPadding = null,
|
extendedPadding = null,
|
||||||
|
extendedTextStyle = null,
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// Creates a small circular floating action button.
|
/// Creates a small circular floating action button.
|
||||||
@ -219,6 +220,7 @@ class FloatingActionButton extends StatelessWidget {
|
|||||||
_extendedLabel = null,
|
_extendedLabel = null,
|
||||||
extendedIconLabelSpacing = null,
|
extendedIconLabelSpacing = null,
|
||||||
extendedPadding = null,
|
extendedPadding = null,
|
||||||
|
extendedTextStyle = null,
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// Creates a large circular floating action button.
|
/// Creates a large circular floating action button.
|
||||||
@ -266,6 +268,7 @@ class FloatingActionButton extends StatelessWidget {
|
|||||||
_extendedLabel = null,
|
_extendedLabel = null,
|
||||||
extendedIconLabelSpacing = null,
|
extendedIconLabelSpacing = null,
|
||||||
extendedPadding = null,
|
extendedPadding = null,
|
||||||
|
extendedTextStyle = 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
|
||||||
@ -298,6 +301,7 @@ class FloatingActionButton extends StatelessWidget {
|
|||||||
this.autofocus = false,
|
this.autofocus = false,
|
||||||
this.extendedIconLabelSpacing,
|
this.extendedIconLabelSpacing,
|
||||||
this.extendedPadding,
|
this.extendedPadding,
|
||||||
|
this.extendedTextStyle,
|
||||||
Widget? icon,
|
Widget? icon,
|
||||||
required Widget label,
|
required Widget label,
|
||||||
this.enableFeedback,
|
this.enableFeedback,
|
||||||
@ -530,6 +534,13 @@ class FloatingActionButton extends StatelessWidget {
|
|||||||
/// provided, and `EdgeInsetsDirectional.only(start: 20.0, end: 20.0)` if not.
|
/// provided, and `EdgeInsetsDirectional.only(start: 20.0, end: 20.0)` if not.
|
||||||
final EdgeInsetsGeometry? extendedPadding;
|
final EdgeInsetsGeometry? extendedPadding;
|
||||||
|
|
||||||
|
/// The text style for an extended [FloatingActionButton]'s label.
|
||||||
|
///
|
||||||
|
/// If null, [FloatingActionButtonThemeData.extendedTextStyle] is used. If
|
||||||
|
/// that is also null, then [TextTheme.button] with a letter spacing of 1.2
|
||||||
|
/// is used.
|
||||||
|
final TextStyle? extendedTextStyle;
|
||||||
|
|
||||||
final _FloatingActionButtonType _floatingActionButtonType;
|
final _FloatingActionButtonType _floatingActionButtonType;
|
||||||
|
|
||||||
final Widget? _extendedLabel;
|
final Widget? _extendedLabel;
|
||||||
@ -580,10 +591,9 @@ class FloatingActionButton extends StatelessWidget {
|
|||||||
?? theme.materialTapTargetSize;
|
?? theme.materialTapTargetSize;
|
||||||
final bool enableFeedback = this.enableFeedback
|
final bool enableFeedback = this.enableFeedback
|
||||||
?? floatingActionButtonTheme.enableFeedback ?? true;
|
?? floatingActionButtonTheme.enableFeedback ?? true;
|
||||||
final TextStyle textStyle = theme.textTheme.button!.copyWith(
|
final TextStyle extendedTextStyle = (this.extendedTextStyle
|
||||||
color: foregroundColor,
|
?? floatingActionButtonTheme.extendedTextStyle
|
||||||
letterSpacing: 1.2,
|
?? theme.textTheme.button!.copyWith(letterSpacing: 1.2)).copyWith(color: foregroundColor);
|
||||||
);
|
|
||||||
final ShapeBorder shape = this.shape
|
final ShapeBorder shape = this.shape
|
||||||
?? floatingActionButtonTheme.shape
|
?? floatingActionButtonTheme.shape
|
||||||
?? (isExtended ? _defaultExtendedShape : _defaultShape);
|
?? (isExtended ? _defaultExtendedShape : _defaultShape);
|
||||||
@ -644,7 +654,7 @@ class FloatingActionButton extends StatelessWidget {
|
|||||||
focusColor: focusColor,
|
focusColor: focusColor,
|
||||||
hoverColor: hoverColor,
|
hoverColor: hoverColor,
|
||||||
splashColor: splashColor,
|
splashColor: splashColor,
|
||||||
textStyle: textStyle,
|
textStyle: extendedTextStyle,
|
||||||
shape: shape,
|
shape: shape,
|
||||||
clipBehavior: clipBehavior,
|
clipBehavior: clipBehavior,
|
||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
|
@ -49,6 +49,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
|
|||||||
this.extendedSizeConstraints,
|
this.extendedSizeConstraints,
|
||||||
this.extendedIconLabelSpacing,
|
this.extendedIconLabelSpacing,
|
||||||
this.extendedPadding,
|
this.extendedPadding,
|
||||||
|
this.extendedTextStyle,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Color to be used for the unselected, enabled [FloatingActionButton]'s
|
/// Color to be used for the unselected, enabled [FloatingActionButton]'s
|
||||||
@ -121,6 +122,9 @@ class FloatingActionButtonThemeData with Diagnosticable {
|
|||||||
/// The padding for an extended [FloatingActionButton]'s content.
|
/// The padding for an extended [FloatingActionButton]'s content.
|
||||||
final EdgeInsetsGeometry? extendedPadding;
|
final EdgeInsetsGeometry? extendedPadding;
|
||||||
|
|
||||||
|
/// The text style for an extended [FloatingActionButton]'s label.
|
||||||
|
final TextStyle? extendedTextStyle;
|
||||||
|
|
||||||
/// 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({
|
||||||
@ -142,6 +146,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
|
|||||||
BoxConstraints? extendedSizeConstraints,
|
BoxConstraints? extendedSizeConstraints,
|
||||||
double? extendedIconLabelSpacing,
|
double? extendedIconLabelSpacing,
|
||||||
EdgeInsetsGeometry? extendedPadding,
|
EdgeInsetsGeometry? extendedPadding,
|
||||||
|
TextStyle? extendedTextStyle,
|
||||||
}) {
|
}) {
|
||||||
return FloatingActionButtonThemeData(
|
return FloatingActionButtonThemeData(
|
||||||
foregroundColor: foregroundColor ?? this.foregroundColor,
|
foregroundColor: foregroundColor ?? this.foregroundColor,
|
||||||
@ -162,6 +167,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
|
|||||||
extendedSizeConstraints: extendedSizeConstraints ?? this.extendedSizeConstraints,
|
extendedSizeConstraints: extendedSizeConstraints ?? this.extendedSizeConstraints,
|
||||||
extendedIconLabelSpacing: extendedIconLabelSpacing ?? this.extendedIconLabelSpacing,
|
extendedIconLabelSpacing: extendedIconLabelSpacing ?? this.extendedIconLabelSpacing,
|
||||||
extendedPadding: extendedPadding ?? this.extendedPadding,
|
extendedPadding: extendedPadding ?? this.extendedPadding,
|
||||||
|
extendedTextStyle: extendedTextStyle ?? this.extendedTextStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,6 +199,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
|
|||||||
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),
|
extendedPadding: EdgeInsetsGeometry.lerp(a?.extendedPadding, b?.extendedPadding, t),
|
||||||
|
extendedTextStyle: TextStyle.lerp(a?.extendedTextStyle, b?.extendedTextStyle, t),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,6 +224,7 @@ class FloatingActionButtonThemeData with Diagnosticable {
|
|||||||
extendedSizeConstraints,
|
extendedSizeConstraints,
|
||||||
extendedIconLabelSpacing,
|
extendedIconLabelSpacing,
|
||||||
extendedPadding,
|
extendedPadding,
|
||||||
|
extendedTextStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +252,8 @@ class FloatingActionButtonThemeData with Diagnosticable {
|
|||||||
&& other.largeSizeConstraints == largeSizeConstraints
|
&& other.largeSizeConstraints == largeSizeConstraints
|
||||||
&& other.extendedSizeConstraints == extendedSizeConstraints
|
&& other.extendedSizeConstraints == extendedSizeConstraints
|
||||||
&& other.extendedIconLabelSpacing == extendedIconLabelSpacing
|
&& other.extendedIconLabelSpacing == extendedIconLabelSpacing
|
||||||
&& other.extendedPadding == extendedPadding;
|
&& other.extendedPadding == extendedPadding
|
||||||
|
&& other.extendedTextStyle == extendedTextStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -269,5 +278,6 @@ class FloatingActionButtonThemeData with Diagnosticable {
|
|||||||
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));
|
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('extendedPadding', extendedPadding, defaultValue: null));
|
||||||
|
properties.add(DiagnosticsProperty<TextStyle>('extendedTextStyle', extendedTextStyle, defaultValue: null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1023,6 +1023,33 @@ void main() {
|
|||||||
expect(tester.getTopRight(find.byType(FloatingActionButton)).dx - tester.getTopRight(find.byKey(labelKey)).dx, padding.end);
|
expect(tester.getTopRight(find.byType(FloatingActionButton)).dx - tester.getTopRight(find.byKey(labelKey)).dx, padding.end);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('FloatingActionButton.extended can customize text style', (WidgetTester tester) async {
|
||||||
|
const Key labelKey = Key('label');
|
||||||
|
const TextStyle style = TextStyle(letterSpacing: 2.0);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
floatingActionButton: FloatingActionButton.extended(
|
||||||
|
label: const Text('', key: labelKey),
|
||||||
|
icon: const Icon(Icons.add),
|
||||||
|
extendedTextStyle: style,
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final RawMaterialButton rawMaterialButton = tester.widget<RawMaterialButton>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(FloatingActionButton),
|
||||||
|
matching: find.byType(RawMaterialButton),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// The color comes from the default color scheme's onSecondary value.
|
||||||
|
expect(rawMaterialButton.textStyle, style.copyWith(color: const Color(0xffffffff)));
|
||||||
|
});
|
||||||
|
|
||||||
group('feedback', () {
|
group('feedback', () {
|
||||||
late FeedbackTester feedback;
|
late FeedbackTester feedback;
|
||||||
|
|
||||||
|
@ -176,12 +176,13 @@ void main() {
|
|||||||
expect(_getRawMaterialButton(tester).constraints, constraints);
|
expect(_getRawMaterialButton(tester).constraints, constraints);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('FloatingActionButton.extended uses custom constraints and spacing when specified in the theme', (WidgetTester tester) async {
|
testWidgets('FloatingActionButton.extended uses custom properties when specified in the theme', (WidgetTester tester) async {
|
||||||
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 iconLabelSpacing = 33.0;
|
const double iconLabelSpacing = 33.0;
|
||||||
const EdgeInsetsDirectional padding = EdgeInsetsDirectional.only(start: 5.0, end: 6.0);
|
const EdgeInsetsDirectional padding = EdgeInsetsDirectional.only(start: 5.0, end: 6.0);
|
||||||
|
const TextStyle textStyle = TextStyle(letterSpacing: 2.0);
|
||||||
|
|
||||||
await tester.pumpWidget(MaterialApp(
|
await tester.pumpWidget(MaterialApp(
|
||||||
theme: ThemeData().copyWith(
|
theme: ThemeData().copyWith(
|
||||||
@ -189,6 +190,7 @@ void main() {
|
|||||||
extendedSizeConstraints: constraints,
|
extendedSizeConstraints: constraints,
|
||||||
extendedIconLabelSpacing: iconLabelSpacing,
|
extendedIconLabelSpacing: iconLabelSpacing,
|
||||||
extendedPadding: padding,
|
extendedPadding: padding,
|
||||||
|
extendedTextStyle: textStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
@ -204,19 +206,23 @@ void main() {
|
|||||||
expect(tester.getTopLeft(find.byKey(labelKey)).dx - tester.getTopRight(find.byKey(iconKey)).dx, iconLabelSpacing);
|
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.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);
|
expect(tester.getTopRight(find.byType(FloatingActionButton)).dx - tester.getTopRight(find.byKey(labelKey)).dx, padding.end);
|
||||||
|
// The color comes from the default color scheme's onSecondary value.
|
||||||
|
expect(_getRawMaterialButton(tester).textStyle, textStyle.copyWith(color: const Color(0xffffffff)));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('FloatingActionButton.extended spacing takes priority over FloatingActionButtonThemeData spacing', (WidgetTester tester) async {
|
testWidgets('FloatingActionButton.extended custom properties 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 iconLabelSpacing = 33.0;
|
const double iconLabelSpacing = 33.0;
|
||||||
const EdgeInsetsDirectional padding = EdgeInsetsDirectional.only(start: 5.0, end: 6.0);
|
const EdgeInsetsDirectional padding = EdgeInsetsDirectional.only(start: 5.0, end: 6.0);
|
||||||
|
const TextStyle textStyle = TextStyle(letterSpacing: 2.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),
|
extendedPadding: EdgeInsetsDirectional.only(start: 7.0, end: 8.0),
|
||||||
|
extendedTextStyle: TextStyle(letterSpacing: 3.0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
@ -226,6 +232,7 @@ void main() {
|
|||||||
icon: const Icon(Icons.add, key: iconKey),
|
icon: const Icon(Icons.add, key: iconKey),
|
||||||
extendedIconLabelSpacing: iconLabelSpacing,
|
extendedIconLabelSpacing: iconLabelSpacing,
|
||||||
extendedPadding: padding,
|
extendedPadding: padding,
|
||||||
|
extendedTextStyle: textStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
@ -233,6 +240,8 @@ void main() {
|
|||||||
expect(tester.getTopLeft(find.byKey(labelKey)).dx - tester.getTopRight(find.byKey(iconKey)).dx, iconLabelSpacing);
|
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.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);
|
expect(tester.getTopRight(find.byType(FloatingActionButton)).dx - tester.getTopRight(find.byKey(labelKey)).dx, padding.end);
|
||||||
|
// The color comes from the default color scheme's onSecondary value.
|
||||||
|
expect(_getRawMaterialButton(tester).textStyle, textStyle.copyWith(color: const Color(0xffffffff)));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('default FloatingActionButton debugFillProperties', (WidgetTester tester) async {
|
testWidgets('default FloatingActionButton debugFillProperties', (WidgetTester tester) async {
|
||||||
@ -268,6 +277,7 @@ void main() {
|
|||||||
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),
|
extendedPadding: EdgeInsetsDirectional.only(start: 7.0, end: 8.0),
|
||||||
|
extendedTextStyle: TextStyle(letterSpacing: 2.0),
|
||||||
).debugFillProperties(builder);
|
).debugFillProperties(builder);
|
||||||
|
|
||||||
final List<String> description = builder.properties
|
final List<String> description = builder.properties
|
||||||
@ -294,6 +304,7 @@ void main() {
|
|||||||
'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)',
|
'extendedPadding: EdgeInsetsDirectional(7.0, 0.0, 8.0, 0.0)',
|
||||||
|
'extendedTextStyle: TextStyle(inherit: true, letterSpacing: 2.0)',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user