Unverified Commit 489d29c1 authored by Hans Muller's avatar Hans Muller Committed by GitHub

Added ButtonStyle.alignment property (#73894)

parent abb48f49
......@@ -114,6 +114,7 @@ class ButtonStyle with Diagnosticable {
this.tapTargetSize,
this.animationDuration,
this.enableFeedback,
this.alignment,
});
/// The style for a button's [Text] widget descendants.
......@@ -208,6 +209,16 @@ class ButtonStyle with Diagnosticable {
/// * [Feedback] for providing platform-specific feedback to certain actions.
final bool? enableFeedback;
/// The alignment of the button's child.
///
/// Typically buttons are sized to be just big enough to contain the child and its
/// padding. If the button's size is constrained to a fixed size, for example by
/// enclosing it with a [SizedBox], this property defines how the child is aligned
/// within the available space.
///
/// Always defaults to [Alignment.center].
final AlignmentGeometry? alignment;
/// Returns a copy of this ButtonStyle with the given fields replaced with
/// the new values.
ButtonStyle copyWith({
......@@ -226,6 +237,7 @@ class ButtonStyle with Diagnosticable {
MaterialTapTargetSize? tapTargetSize,
Duration? animationDuration,
bool? enableFeedback,
AlignmentGeometry? alignment,
}) {
return ButtonStyle(
textStyle: textStyle ?? this.textStyle,
......@@ -243,6 +255,7 @@ class ButtonStyle with Diagnosticable {
tapTargetSize: tapTargetSize ?? this.tapTargetSize,
animationDuration: animationDuration ?? this.animationDuration,
enableFeedback: enableFeedback ?? this.enableFeedback,
alignment: alignment ?? this.alignment,
);
}
......@@ -270,6 +283,7 @@ class ButtonStyle with Diagnosticable {
tapTargetSize: tapTargetSize ?? style.tapTargetSize,
animationDuration: animationDuration ?? style.animationDuration,
enableFeedback: enableFeedback ?? style.enableFeedback,
alignment: alignment ?? style.alignment,
);
}
......@@ -291,6 +305,7 @@ class ButtonStyle with Diagnosticable {
tapTargetSize,
animationDuration,
enableFeedback,
alignment,
);
}
......@@ -315,7 +330,8 @@ class ButtonStyle with Diagnosticable {
&& other.visualDensity == visualDensity
&& other.tapTargetSize == tapTargetSize
&& other.animationDuration == animationDuration
&& other.enableFeedback == enableFeedback;
&& other.enableFeedback == enableFeedback
&& other.alignment == alignment;
}
@override
......@@ -336,6 +352,7 @@ class ButtonStyle with Diagnosticable {
properties.add(EnumProperty<MaterialTapTargetSize>('tapTargetSize', tapTargetSize, defaultValue: null));
properties.add(DiagnosticsProperty<Duration>('animationDuration', animationDuration, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('enableFeedback', enableFeedback, defaultValue: null));
properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null));
}
/// Linearly interpolate between two [ButtonStyle]s.
......@@ -359,6 +376,7 @@ class ButtonStyle with Diagnosticable {
tapTargetSize: t < 0.5 ? a?.tapTargetSize : b?.tapTargetSize,
animationDuration: t < 0.5 ? a?.animationDuration : b?.animationDuration,
enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback,
alignment: AlignmentGeometry.lerp(a?.alignment, b?.alignment, t),
);
}
......
......@@ -283,6 +283,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
final MaterialTapTargetSize? resolvedTapTargetSize = effectiveValue((ButtonStyle? style) => style?.tapTargetSize);
final Duration? resolvedAnimationDuration = effectiveValue((ButtonStyle? style) => style?.animationDuration);
final bool? resolvedEnableFeedback = effectiveValue((ButtonStyle? style) => style?.enableFeedback);
final AlignmentGeometry? resolvedAlignment = effectiveValue((ButtonStyle? style) => style?.alignment);
final Offset densityAdjustment = resolvedVisualDensity!.baseSizeAdjustment;
final BoxConstraints effectiveConstraints = resolvedVisualDensity.effectiveConstraints(
BoxConstraints(
......@@ -360,7 +361,8 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
data: IconThemeData(color: resolvedForegroundColor),
child: Padding(
padding: padding,
child: Center(
child: Align(
alignment: resolvedAlignment!,
widthFactor: 1.0,
heightFactor: 1.0,
child: widget.child,
......
......@@ -147,6 +147,7 @@ class ElevatedButton extends ButtonStyleButton {
MaterialTapTargetSize? tapTargetSize,
Duration? animationDuration,
bool? enableFeedback,
AlignmentGeometry? alignment,
}) {
final MaterialStateProperty<Color?>? backgroundColor = (onSurface == null && primary == null)
? null
......@@ -180,6 +181,7 @@ class ElevatedButton extends ButtonStyleButton {
tapTargetSize: tapTargetSize,
animationDuration: animationDuration,
enableFeedback: enableFeedback,
alignment: alignment,
);
}
......@@ -238,6 +240,7 @@ class ElevatedButton extends ButtonStyleButton {
/// * `tapTargetSize` - theme.materialTapTargetSize
/// * `animationDuration` - kThemeChangeDuration
/// * `enableFeedback` - true
/// * `alignment` - Alignment.center
///
/// The default padding values for the [ElevatedButton.icon] factory are slightly different:
///
......@@ -280,6 +283,7 @@ class ElevatedButton extends ButtonStyleButton {
tapTargetSize: theme.materialTapTargetSize,
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
);
}
......
......@@ -139,6 +139,7 @@ class OutlinedButton extends ButtonStyleButton {
MaterialTapTargetSize? tapTargetSize,
Duration? animationDuration,
bool? enableFeedback,
AlignmentGeometry? alignment,
}) {
final MaterialStateProperty<Color?>? foregroundColor = (onSurface == null && primary == null)
? null
......@@ -166,6 +167,7 @@ class OutlinedButton extends ButtonStyleButton {
tapTargetSize: tapTargetSize,
animationDuration: animationDuration,
enableFeedback: enableFeedback,
alignment: alignment,
);
}
......@@ -217,6 +219,7 @@ class OutlinedButton extends ButtonStyleButton {
/// * `tapTargetSize` - theme.materialTapTargetSize
/// * `animationDuration` - kThemeChangeDuration
/// * `enableFeedback` - true
/// * `alignment` - Alignment.center
@override
ButtonStyle defaultStyleOf(BuildContext context) {
final ThemeData theme = Theme.of(context);
......@@ -249,6 +252,7 @@ class OutlinedButton extends ButtonStyleButton {
tapTargetSize: theme.materialTapTargetSize,
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
);
}
......
......@@ -145,6 +145,7 @@ class TextButton extends ButtonStyleButton {
MaterialTapTargetSize? tapTargetSize,
Duration? animationDuration,
bool? enableFeedback,
AlignmentGeometry? alignment,
}) {
final MaterialStateProperty<Color?>? foregroundColor = (onSurface == null && primary == null)
? null
......@@ -172,6 +173,7 @@ class TextButton extends ButtonStyleButton {
tapTargetSize: tapTargetSize,
animationDuration: animationDuration,
enableFeedback: enableFeedback,
alignment: alignment,
);
}
......@@ -226,6 +228,7 @@ class TextButton extends ButtonStyleButton {
/// * `tapTargetSize` - theme.materialTapTargetSize
/// * `animationDuration` - kThemeChangeDuration
/// * `enableFeedback` - true
/// * `alignment` - Alignment.center
///
/// The default padding values for the [TextButton.icon] factory are slightly different:
///
......@@ -267,6 +270,7 @@ class TextButton extends ButtonStyleButton {
tapTargetSize: theme.materialTapTargetSize,
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
);
}
......
......@@ -48,6 +48,9 @@ void main() {
expect(material.textStyle!.fontWeight, FontWeight.w500);
expect(material.type, MaterialType.button);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.text('button'), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
final Offset center = tester.getCenter(find.byType(ElevatedButton));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(); // start the splash animation
......
......@@ -39,6 +39,9 @@ void main() {
expect(material.textStyle!.fontFamily, 'Roboto');
expect(material.textStyle!.fontSize, 14);
expect(material.textStyle!.fontWeight, FontWeight.w500);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.text('button'), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
});
group('[Theme, TextTheme, ElevatedButton style overrides]', () {
......@@ -57,6 +60,7 @@ void main() {
const MaterialTapTargetSize tapTargetSize = MaterialTapTargetSize.shrinkWrap;
const Duration animationDuration = Duration(milliseconds: 25);
const bool enableFeedback = false;
const AlignmentGeometry alignment = Alignment.centerLeft;
final ButtonStyle style = ElevatedButton.styleFrom(
primary: primaryColor,
......@@ -74,6 +78,7 @@ void main() {
tapTargetSize: tapTargetSize,
animationDuration: animationDuration,
enableFeedback: enableFeedback,
alignment: alignment,
);
Widget buildFrame({ ButtonStyle? buttonStyle, ButtonStyle? themeStyle, ButtonStyle? overallStyle }) {
......@@ -137,6 +142,8 @@ void main() {
expect(material.shape, shape);
expect(material.animationDuration, animationDuration);
expect(tester.getSize(find.byType(ElevatedButton)), const Size(200, 200));
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.text('button'), matching: find.byType(Align)));
expect(align.alignment, alignment);
}
testWidgets('Button style overrides defaults', (WidgetTester tester) async {
......
......@@ -52,6 +52,9 @@ void main() {
expect(material.textStyle!.fontWeight, FontWeight.w500);
expect(material.type, MaterialType.button);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.text('button'), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
final Offset center = tester.getCenter(find.byType(OutlinedButton));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(); // start the splash animation
......
......@@ -44,6 +44,9 @@ void main() {
expect(material.textStyle!.fontFamily, 'Roboto');
expect(material.textStyle!.fontSize, 14);
expect(material.textStyle!.fontWeight, FontWeight.w500);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.text('button'), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
});
group('[Theme, TextTheme, OutlinedButton style overrides]', () {
......@@ -62,6 +65,7 @@ void main() {
const MaterialTapTargetSize tapTargetSize = MaterialTapTargetSize.shrinkWrap;
const Duration animationDuration = Duration(milliseconds: 25);
const bool enableFeedback = false;
const AlignmentGeometry alignment = Alignment.centerLeft;
final ButtonStyle style = OutlinedButton.styleFrom(
primary: primaryColor,
......@@ -79,6 +83,7 @@ void main() {
tapTargetSize: tapTargetSize,
animationDuration: animationDuration,
enableFeedback: enableFeedback,
alignment: alignment,
);
Widget buildFrame({ ButtonStyle? buttonStyle, ButtonStyle? themeStyle, ButtonStyle? overallStyle }) {
......@@ -140,6 +145,8 @@ void main() {
expect(material.shape, shape);
expect(material.animationDuration, animationDuration);
expect(tester.getSize(find.byType(OutlinedButton)), const Size(200, 200));
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.text('button'), matching: find.byType(Align)));
expect(align.alignment, alignment);
}
testWidgets('Button style overrides defaults', (WidgetTester tester) async {
......
......@@ -47,6 +47,9 @@ void main() {
expect(material.textStyle!.fontWeight, FontWeight.w500);
expect(material.type, MaterialType.button);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.text('button'), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
final Offset center = tester.getCenter(find.byType(TextButton));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(); // start the splash animation
......
......@@ -39,6 +39,9 @@ void main() {
expect(material.textStyle!.fontFamily, 'Roboto');
expect(material.textStyle!.fontSize, 14);
expect(material.textStyle!.fontWeight, FontWeight.w500);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.text('button'), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
});
group('[Theme, TextTheme, TextButton style overrides]', () {
......@@ -57,6 +60,7 @@ void main() {
const MaterialTapTargetSize tapTargetSize = MaterialTapTargetSize.shrinkWrap;
const Duration animationDuration = Duration(milliseconds: 25);
const bool enableFeedback = false;
const AlignmentGeometry alignment = Alignment.centerLeft;
final ButtonStyle style = TextButton.styleFrom(
primary: primaryColor,
......@@ -74,6 +78,7 @@ void main() {
tapTargetSize: tapTargetSize,
animationDuration: animationDuration,
enableFeedback: enableFeedback,
alignment: alignment,
);
Widget buildFrame({ ButtonStyle? buttonStyle, ButtonStyle? themeStyle, ButtonStyle? overallStyle }) {
......@@ -135,6 +140,8 @@ void main() {
expect(material.shape, shape);
expect(material.animationDuration, animationDuration);
expect(tester.getSize(find.byType(TextButton)), const Size(200, 200));
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.text('button'), matching: find.byType(Align)));
expect(align.alignment, alignment);
}
testWidgets('Button style overrides defaults', (WidgetTester tester) async {
......
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