在上篇文章 使用 Flutter Button 介绍了如何修改 button 的样式,本文来具体实践一下。
本文列举一些常用的 button 效果,以便在用到的时候方便使用。因为 ElevatedButton 最常用,所以大多以 ElevatedButton 举例。
ElevatedButton 一般是用做主 button 的。之所以叫 ElevatedButton 是因为按下的时候会有 elevation 变大的效果。
去掉水波效果
ElevatedButton( child: Text('IAM17'), style: ButtonStyle(splashFactory: NoSplash.splashFactory), onPressed: () {}, ) 复制代码
监听状态变化
class _MyWidgetState extends State<MyWidget> { late MaterialStatesController controller; @override void initState() { controller = MaterialStatesController(); controller.addListener(() { print(controller.value); }); super.initState(); } @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return ElevatedButton( statesController: controller, onPressed: () {}, child: Text('IAM17'), ); } } 复制代码
比如当按住按钮的时候,会输出 {MaterialState.pressed}
,当松开按钮的时候会输出{}
。被禁用的时候输出{MaterialState.disabled}
。
shape 动画,size 和 文字样式
class _MyWidgetState extends State<MyWidget> { var elevation = 10.0; OutlinedBorder shape = CircleBorder(); @override void initState() { super.initState(); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return ElevatedButton( clipBehavior: Clip.hardEdge, style: ElevatedButton.styleFrom( fixedSize: Size(100, 100), textStyle:TextStyle(fontSize: 20), shape: shape, animationDuration: Duration(milliseconds: 600), elevation: elevation), onPressed: () { setState(() { elevation = elevation == 10 ? 20 : 10; shape = shape is CircleBorder ? RoundedRectangleBorder(borderRadius:BorderRadius.circular(10)) : CircleBorder(); }); }, child: Text('IAM17'), ); } } 复制代码
animationDuration 可以为 elevation 和 shape 提供动画支持。本例中,按钮从圆形和矩形之间不断变换,除了 shape 变化,elevation(投影)也会随着变化。
默认情况下 clip.none。如果按钮的文字过长会溢出。设置 clip.hardEdget 防止溢出。
fixedSize 设置按钮的大小,当然了,会受到最大最小值和父级的约束影响。
文字样式写在 style 的 textStyle ,不要去 child 的 Text 那里写。
foregroundColor、backgroundColor 和 overlayColor
ElevatedButton.styleFrom( splashFactory: NoSplash.splashFactory, foregroundColor: Colors.amber, backgroundColor:Colors.green, ) 复制代码
foregroundColor 是文字的颜色。别去 child 的 Text 设置文字颜色了。
backgroundColor 是背景色。
当按下按钮的时候显示的是 overlayColor,一般是一个半透明的,覆盖在 backgroundColor 上面,child 的下面。styleFrom 是不能设置 overlayColor 的。overlayColor 直接取 foregroundColor 并设置好的透明度,一般情况下我们不需要单独设置。单独设置 overlayColor 可以用 ButtonStyle。
ButtonStyle( splashFactory: NoSplash.splashFactory, foregroundColor: MaterialStateProperty.all<Color>(Colors.amber), backgroundColor: MaterialStateProperty.all<Color>(Colors.green), overlayColor: MaterialStateProperty.all<Color>(Colors.pink), ) 复制代码
ButtonStyle 设置的 overlayColor 是不会自动加上透明效果,如果要透明,需要自己加透明效果。比如Color.fromRGBO(0, 0, 0, .2)
。
disabled color
ElevatedButton( style:ElevatedButton.styleFrom( disabledBackgroundColor: Colors.grey, disabledForegroundColor:Colors.black54 ), onPressed: null, child: Text('IAM17'), ) 复制代码
按钮 disabled 后,按下去不会有反应了。只需要设置好 disabledBackgroundColor 和 disabledForegroundColor 即可,overlayColor 不需要设置了。
给按钮加边框
style:ElevatedButton.styleFrom( side: BorderSide() ), 复制代码
圆形
加边框很简单,side 属性就可以办到。和shape 配合可以做出各种形状的 border,比如圆形 border。
style:ElevatedButton.styleFrom( shape: CircleBorder(), fixedSize: Size(80,80), side: BorderSide(color: Colors.red,width: 4,strokeAlign: StrokeAlign.inside) 复制代码
strokeAlign 参数表示border 是画在shape 的外部,内部还是中间。如果 clipBehavior
不为 Clip.none
, 那么最好设置为 StrokeAlign.inside
。
还有几种 shape 也一起介绍下吧。其实这些 shape 先有个印象即可,知道有这些 shape 可以用。
BeveledRectangle
style:ElevatedButton.styleFrom( shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(20)), fixedSize: Size(120,80), side: BorderSide(color: Colors.red,width: 4)) 复制代码
ContinuousRectangle
style:ElevatedButton.styleFrom( shape: ContinuousRectangleBorder( borderRadius: BorderRadius.circular(40)), fixedSize: Size(120,80), side: BorderSide(color: Colors.red,width: 4)) 复制代码
RoundedRectangle
style:ElevatedButton.styleFrom( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)), fixedSize: Size(80,80), side: BorderSide(color: Colors.red,width: 4), 复制代码
如果把 30 改变为 40 就变成圆形了。
stadium
style:ElevatedButton.styleFrom( shape: StadiumBorder(), fixedSize: Size(120,80), side: BorderSide(color: Colors.red,width: 4), 复制代码
stadium 的中文含意是 体育场,我们看形状也还真挺像的。
不知道你注意到没有 和 Text 的样式一样,side 也可以写在 各种 border 里面。但我们写的时候,最好都写在外面的 side 参数那里。
OutlineButton
OutlineButton 自带边框,没有背景色,没有 elevation。通常不作为主操作按钮。
带 icon 的 button
ElevatedButton.icon( onPressed: () {}, icon: Icon(Icons.account_box), label: Text('IAM17')); 复制代码
Flutter 这里还是很贴心的,为我们准备了 icon 命名构造函数。 OulineButton,TextButton也都有 icon 的构造函数。其实内部实现就是用了一个 Row。
如果只有一个 icon,那么可以用 IconButton 了。
渐变背景 button
ClipRRect( borderRadius: BorderRadius.circular(4), child: Stack( children: <Widget>[ Positioned.fill( child: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: <Color>[ Color(0xFF0D47A1), Color(0xFF1976D2), Color(0xFF42A5F5), ], ), ), ), ), TextButton( style: TextButton.styleFrom( foregroundColor: Colors.white, padding: const EdgeInsets.all(16.0), textStyle: const TextStyle(fontSize: 20), ), onPressed: () {}, child: const Text('IAM17'), ), ], ), ) 复制代码
由于背景色只能用 Color ,所以要做出一个渐变背景色的 button 还是很麻烦的,需要叠加才行。最后还得用 ClipRRect 剪裁成圆角。