深色模式
Button
常用的Button
ElevatedButton
- a filled button whose material elevates when pressed.FilledButton
- a filled button that doesn't elevate when pressed.FilledButton.tonal
- a filled button variant that uses a secondary fill color.OutlinedButton
- a button with an outlined border and no fill color.TextButton
- a button with no outline or fill color.
Button的默认尺寸
先说结论:
对于ElevatedButton
、OutlinedButton
、TextButton
,最小宽度64,高度36,最大则不限制。
对于FilledButton
,最小宽度64,高度40,最大则不限制。
再看源码:
ElevatedButton
、OutlinedButton
、TextButton
定义默认尺寸的代码是一样的,以OutlinedButton
为例,源码在src/material/outlined_button.dart
中,OutlinedButton
有一个defaultStyleOf
方法
dart
@override
ButtonStyle defaultStyleOf(BuildContext context) {
final ThemeData theme = Theme.of(context);
final ColorScheme colorScheme = theme.colorScheme;
return Theme.of(context).useMaterial3
? _OutlinedButtonDefaultsM3(context)
: styleFrom(
foregroundColor: colorScheme.primary,
disabledForegroundColor: colorScheme.onSurface.withOpacity(0.38),
backgroundColor: Colors.transparent,
disabledBackgroundColor: Colors.transparent,
shadowColor: theme.shadowColor,
elevation: 0,
textStyle: theme.textTheme.labelLarge,
padding: _scaledPadding(context),
minimumSize: const Size(64, 36),
maximumSize: Size.infinite,
side: BorderSide(
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12),
),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))),
enabledMouseCursor: SystemMouseCursors.click,
disabledMouseCursor: SystemMouseCursors.basic,
visualDensity: theme.visualDensity,
tapTargetSize: theme.materialTapTargetSize,
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
splashFactory: InkRipple.splashFactory,
);
}
而FilledButton
,源码路径类似,在src/material/filled_button.dart
,默认尺寸与上面不同
dart
@override
ButtonStyle defaultStyleOf(BuildContext context) {
switch (_variant) {
case _FilledButtonVariant.filled:
return _FilledButtonDefaultsM3(context);
case _FilledButtonVariant.tonal:
return _FilledTonalButtonDefaultsM3(context);
}
}
dart
@override
MaterialStateProperty<Size>? get minimumSize =>
const MaterialStatePropertyAll<Size>(Size(64.0, 40.0));
// No default fixedSize
@override
MaterialStateProperty<Size>? get maximumSize =>
const MaterialStatePropertyAll<Size>(Size.infinite);
Button内间距
间距不是固定的,受到主题中的textTheme.labelLarge.fontSize
影响
以OutlinedButton为例
dart
@override
ButtonStyle defaultStyleOf(BuildContext context) {
final ThemeData theme = Theme.of(context);
final ColorScheme colorScheme = theme.colorScheme;
return Theme.of(context).useMaterial3
? _OutlinedButtonDefaultsM3(context)
: styleFrom(
foregroundColor: colorScheme.primary,
disabledForegroundColor: colorScheme.onSurface.withOpacity(0.38),
backgroundColor: Colors.transparent,
disabledBackgroundColor: Colors.transparent,
shadowColor: theme.shadowColor,
elevation: 0,
textStyle: theme.textTheme.labelLarge,
padding: _scaledPadding(context),
minimumSize: const Size(64, 36),
maximumSize: Size.infinite,
side: BorderSide(
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12),
),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4))),
enabledMouseCursor: SystemMouseCursors.click,
disabledMouseCursor: SystemMouseCursors.basic,
visualDensity: theme.visualDensity,
tapTargetSize: theme.materialTapTargetSize,
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
splashFactory: InkRipple.splashFactory,
);
}
dart
EdgeInsetsGeometry _scaledPadding(BuildContext context) {
final ThemeData theme = Theme.of(context);
final double padding1x = theme.useMaterial3 ? 24.0 : 16.0;
final double defaultFontSize = theme.textTheme.labelLarge?.fontSize ?? 14.0;
final double effectiveTextScale = MediaQuery.textScalerOf(context).scale(defaultFontSize) / 14.0;
return ButtonStyleButton.scaledPadding(
EdgeInsets.symmetric(horizontal: padding1x),
EdgeInsets.symmetric(horizontal: padding1x / 2),
EdgeInsets.symmetric(horizontal: padding1x / 2 / 2),
effectiveTextScale,
);
}
dart
static EdgeInsetsGeometry scaledPadding(
EdgeInsetsGeometry geometry1x,
EdgeInsetsGeometry geometry2x,
EdgeInsetsGeometry geometry3x,
double fontSizeMultiplier,
) {
return switch (fontSizeMultiplier) {
<= 1 => geometry1x,
< 2 => EdgeInsetsGeometry.lerp(geometry1x, geometry2x, fontSizeMultiplier - 1)!,
< 3 => EdgeInsetsGeometry.lerp(geometry2x, geometry3x, fontSizeMultiplier - 2)!,
_ => geometry3x,
};
}
修改Button的尺寸
Button
的尺寸由minimumSize
、maximumSize
、fixedSize
共同决定,并且fixedSize
受到minimumSize
、maximumSize
的约束。
fixedSize
决定了Button
的默认大小
minimumSize
的作用是,当文字太少时,Button
最小的尺寸
maximumSize
的作用是,当文字太多时,Button
最大的尺寸
Button的形状
Button有默认的形状,可以通过对应Button
的styleFrom()
中的shape
来修改
dart
final button = OutlinedButton(
onPressed: () {},
style: OutlinedButton.styleFrom(
// shape: const StarBorder(),
// shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
// shape: OvalBorder(),
// shape: CircleBorder(),
// shape: ContinuousRectangleBorder(borderRadius: BorderRadius.circular(24))
// shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(24))
// shape: LinearBorder(start: LinearBorderEdge())
shape: StadiumBorder()),
child: Text('展示样式'),
);