版权声明:本文为作者原创书籍。转载请注明作者和出处,未经授权,严禁私自转载,侵权必究!!!
情感语录:得之坦然,失之淡然;争其必然,顺其自然!
欢迎来到本章节,上一章节我们讲了侧边栏
的使用,知识点回顾 戳这里 Flutter基础第七章
本章节将对Flutter中的按钮组件进行介绍,在前面章节的讲解中,其实已经使用到了一些按钮组件,比如 RaisedButton
、IconButton
当然在Flutter中可不止这两个按钮,本篇会将常用的按钮组件都进行罗列讲解。
本章简要:
1、RaisedButton :Material Design 风格的凸起按钮
2、FlatButton :扁平化的按钮
3、OutlineButton:线框按钮
4、IconButton :图标按钮
5、ButtonBar:按钮组
6、FloatingActionButton:浮动按钮
7、自定义实现(左,上,右,下)的图标按钮
8、实战 闲鱼app 底部不规则按钮
按钮组件中的通用属性:
名称 属性值
onPressed 按下按钮时触发的回调,接收一个方法,不填或者传 null 表示按钮禁用
child 文本控件
textColor 文本颜色
color 按钮的颜色
disabledColor 按钮禁用时的颜色
disabledTextColor 按钮禁用时的文本颜色
splashColor 点击按钮时水波纹的颜色
highlightColor 点击(长按)按钮后按钮的颜色
elevation 阴影的范围,值越大阴影范围越大
padding 内边距
shape 设置按钮的形状:
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
)
shape: CircleBorder(
side: BorderSide(color: Colors.white)
)
一 、RaisedButton :
RaisedButton 是 Flutter 提供的 Material 风格的按钮,onPressed
属性可以传递 null 值,如果传递了 null 值或者不写也为null,整个按钮是不可点击的,disabled 状态(灰色)
构造函数如下:
const RaisedButton({
Key key,
@required VoidCallback onPressed,
ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Color color,
Color disabledColor,
Color focusColor,
Color hoverColor,
Color highlightColor,
Color splashColor,
Brightness colorBrightness,
double elevation,
double focusElevation,
double hoverElevation,
double highlightElevation,
double disabledElevation,
EdgeInsetsGeometry padding,
ShapeBorder shape,
Clip clipBehavior,
FocusNode focusNode,
MaterialTapTargetSize materialTapTargetSize,
Duration animationDuration,
Widget child,
})
1、普通 Button 及背景颜色控制、阴影控制
import 'package:flutter/material.dart';
class RaisedButtonPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("RaisedButtonPage"),
),
body: Column(
children: <Widget>[
Row(
children: <Widget>[
SizedBox(width: 5),
RaisedButton(
child: Text('无事件按钮'),
),
SizedBox(width: 5),
RaisedButton(
child: Text('普通按钮'),
onPressed: () {},
),
SizedBox(width: 5),
RaisedButton(
color: Colors.pink,
textColor: Colors.white,
child: Text('颜色按钮'),
onPressed: () {},
),
SizedBox(width: 5),
RaisedButton(
elevation: 20,
focusElevation: 40,
child: Text('阴影按钮'),
onPressed: () {},
),
],
)
],
)
)
);
}
}
效果如下:
RaisedButton1.gif
2、控制 Button 的宽度和高度
RaisedButton 本身没有宽度和高度的属性控制,也没有 margin 属性可利用,如果要指定宽度和高度,可以借助 Container 容器,设置 Container 宽度和高度达到控制 RaisedButton 宽高,或者其他能设置宽高的布局widget也可以,如 :SizedBox
等
Row(
children: <Widget>[
SizedBox(width: 5),
Container(
width: 200,
height: 50,
child: RaisedButton(
child: Text('宽:200,高:50 按钮'),
onPressed: () {},
),
),
SizedBox(width: 5),
Container(
width: 220,
height: 40,
child: RaisedButton(
color: Colors.pink,
textColor: Colors.white,
child: Text('宽:220,高:40 按钮'),
onPressed: () {},
),
)
],
)
效果如下:
RaisedButton2.gif3、宽度自适应按钮
某些场景下,我们可能期望一个 Button 充满整个屏幕宽度。和宽度高度的控制一样,我们需要借助 Row + Expanded ,或者使用 无穷值 double.infinity
方式。
Row(
children: <Widget>[
Expanded(
child: Container(
height: 50,
child: RaisedButton(
child: Text('组合控制自适应'),
onPressed: () {},
),
),
)
],
),
SizedBox(height: 30),
Container(
width: double.infinity,
height: 40,
child: RaisedButton(
color: Colors.pink,
textColor: Colors.white,
child: Text('无穷宽值方式'),
onPressed: () {},
),
)
效果如下:
RaisedButton3.gif4、圆角 & 圆形 按钮
RasedButton 圆角可以通过 shape 属性控制,shape 属性支持传入 RoundedRectangleBorder 并且指定 RoundedRectangleBorder.borderRadius 的圆角值实现按钮圆角。
RaisedButton(
child: Text('圆角按钮',style: TextStyle(color: Colors.white)),
color: Colors.green,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
onPressed: () {},
),
效果如下:
RaisedButton4.pngRasedButton 圆形可以借助 RaisedButton.shape 来实现,本身 shape 支持传入的属性是 ShapeBorder 即可,而 CircleBorder 也是继承自 ShapeBorder。需要注意的是通过这种方式实现圆形按钮,当内部文字过长就会显示不出来,需要外部容器包装下。
SizedBox(
height: 70,
child: RaisedButton(
child: Text('圆形按钮',style: TextStyle(color: Colors.white)),
color: Colors.green,
shape: CircleBorder(
side: BorderSide(color: Colors.blue),
),
onPressed: () {},
),
),
效果如下:
RaisedButton5.png5、图标按钮
造函数 RaisedButton.icon 中可以配置一个带有图标的按钮。
factory RaisedButton.icon({
Key key,
@required VoidCallback onPressed,
ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Color color,
Color disabledColor,
Color focusColor,
Color hoverColor,
Color highlightColor,
Color splashColor,
Brightness colorBrightness,
double elevation,
double highlightElevation,
double disabledElevation,
ShapeBorder shape,
Clip clipBehavior,
FocusNode focusNode,
MaterialTapTargetSize materialTapTargetSize,
Duration animationDuration,
@required Widget icon,
@required Widget label,
}) = _RaisedButtonWithIcon;
运用下这种方式:
RaisedButton.icon(
color: Colors.pink,
textColor: Colors.white,
icon: Icon(Icons.settings),
label: Text('图标按钮'),
onPressed: () {},
),
效果如下:
RaisedButton6.gif开发中这种带有图标的按钮还是非常常见的,不过很遗憾的事 Flutter 就只给我们提供了图标放在左边的这种方式,那如果我想实现像Android 原生 TextView
那样 左,上,右,下都可以定制一个图标那该怎么办呢?
首先我们去看下Flutter中是怎么实现放置一个 Icon 的,跟进 RaisedButton.icon
源码:
/// The type of of RaisedButtons created with [RaisedButton.icon].
///
/// This class only exists to give RaisedButtons created with [RaisedButton.icon]
/// a distinct class for the sake of [ButtonTheme]. It can not be instantiated.
class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixin {
_RaisedButtonWithIcon({
Key key,
@required VoidCallback onPressed,
ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme,
.....
.....
.....
@required Widget icon,
@required Widget label,
}) : assert(elevation == null || elevation >= 0.0),
assert(highlightElevation == null || highlightElevation >= 0.0),
assert(disabledElevation == null || disabledElevation >= 0.0),
assert(icon != null),
assert(label != null),
super(
key: key,
onPressed: onPressed,
.....
.....
.....
focusNode: focusNode,
materialTapTargetSize: materialTapTargetSize,
animationDuration: animationDuration,
child: Row( // 标记1
mainAxisSize: MainAxisSize.min,
children: <Widget>[
icon,
const SizedBox(width: 8.0),
label,
],
),
);
删掉些无用相关代码,(标记1)
发现其实很简单,就是定义了个 icon,然后,把这个 icon和 label用 Row 给包起来了,按照他这种方式,我们也可以去实现其他方位的图标添加了,比如我想实现顶部一个图标的我就用 Column
组件去包装一个 Icon 和 一个Text 方式 ,如果想实现右边有个Icon的,我也用Row
组件去包装,不过我先放Text 组件 然后在放 Icon组件。
不过每次都要这样去写是不是很麻烦啊,能像原生一样简单点吗? 没办法自己撸一个吧,我们先自定义一个类似于Android中支持 android:drawableLeft , android:drawableTop , android:drawableRight , android:drawableBottom ,的多功能按钮 如下:
import 'package:flutter/material.dart';
class FunIconButton extends MaterialButton with MaterialButtonWithIconMixin {
FunIconButton({
Key key,
@required VoidCallback onPressed,
ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Color color,
Color disabledColor,
Color focusColor,
Color hoverColor,
Color highlightColor,
Color splashColor,
Brightness colorBrightness,
double elevation,
double highlightElevation,
double disabledElevation,
ShapeBorder shape,
Clip clipBehavior = Clip.none,
FocusNode focusNode,
MaterialTapTargetSize materialTapTargetSize,
Duration animationDuration,
double minWidth,
double height,
Widget leftIcon,
Widget topIcon,
Widget rightIcon,
Widget bottomIcon,
EdgeInsetsGeometry textPadding,
Widget label,
}) : assert(elevation == null || elevation >= 0.0),
assert(highlightElevation == null || highlightElevation >= 0.0),
assert(disabledElevation == null || disabledElevation >= 0.0),
super(
key: key,
onPressed: onPressed,
onHighlightChanged: onHighlightChanged,
textTheme: textTheme,
textColor: textColor,
disabledTextColor: disabledTextColor,
color: color,
disabledColor: disabledColor,
focusColor: focusColor,
hoverColor: hoverColor,
highlightColor: highlightColor,
splashColor: splashColor,
colorBrightness: colorBrightness,
elevation: elevation,
highlightElevation: highlightElevation,
disabledElevation: disabledElevation,
shape: shape,
clipBehavior: clipBehavior,
focusNode: focusNode,
materialTapTargetSize: materialTapTargetSize,
animationDuration: animationDuration,
minWidth: minWidth,
height: height,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Offstage(
offstage: topIcon == null,
child: topIcon,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Offstage(
offstage: leftIcon == null,
child: leftIcon,
),
Padding(
padding: textPadding,
child: label,
),
Offstage(
offstage: rightIcon == null,
child: rightIcon,
),
],
),
Offstage(
offstage: bottomIcon == null,
child: bottomIcon,
),
],
),
);
}
除了支持 Flutter Button中常用的属性外,我们还添了如下属性:
属性名 类型 作用
leftIcon Widget 左边添加一个图标,可以是其他 Widget 组件
topIcon Widget 顶部添加一个图标,同理
rightIcon Widget 右边添加一个图标,同理
bottomIcon Widget 底部添加一个图标,同理
leftIcon
接收的是一个 Widget 能很好拓展你放其他的组件进去,不一定就是一个图标,为了更加灵活。下面来运用试试。
FunIconButton(
label:Text('多功能按钮',style: TextStyle(color: Colors.deepPurple)),
color: Colors.blue,
textColor: Colors.white,
onPressed: () {},
minWidth: 240,
leftIcon: Image.asset(
"images/mm.jpg",
width: 24,
height: 24,
),
rightIcon: Icon(Icons.group),
topIcon: Icon(Icons.save),
bottomIcon: Icon(Icons.score),
textPadding: EdgeInsets.only(left: 10, right: 10),
),
效果如下:
自定义RaisedButton7.gif二、FlatButton
FlatButton 没有 RaisedButton 默认的阴影,因此看起来是扁平化的,没有凸出感觉。
FlatButton(
//按钮文字颜色
textColor: Colors.white,
//按钮禁用时的背景颜色
disabledColor:Colors.grey,
//按钮禁用时的文字颜色
disabledTextColor: Colors.grey,
//正常状态下的背景颜色
color: Colors.blue,
//按钮按下时的背景颜色
highlightColor: Colors.blue[700],
//按钮主题,默认是浅色主题
colorBrightness: Brightness.dark,
//外形
splashColor: Colors.grey,
// button 显示的文字
child: Text("纳尼"),
//圆角边框
shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
//按钮点击回调
onPressed: () => {},
)
FlatButton.png
三、OutlineButton 边框按钮
OutlineButton 允许我们给 Button 指定 边框和样式,开发中这种 Button 非常常见,运用下:
OutlineButton(
child: Text('边框按钮'),
onPressed: () {},
),
OutlineButton(
borderSide: BorderSide(color: Colors.pink),
child: Text('边框按钮'),
onPressed: () {},
),
效果如下:
OutlineButton.gif四、IconButton 图标按钮
此 Button 已经在案例中使用太多次了,常用且简单。 IconButton 默认实现了高度和宽度的设置,并且是一个圆形的 Button,因此在使用 IconButton 的时候我们可以通过 Icon.size 控制图标大小,也能够控制 padding 属性。
//IconButton
IconButton(
splashColor: Colors.pink,
color: Colors.pink,
icon: Icon(Icons.send,size: 50,),
onPressed: () {},
),
IconButton(
splashColor: Colors.pink,
color: Colors.pink,
padding: EdgeInsets.all(0),
icon: Icon(Icons.settings),
onPressed: () {},
)
效果如下:
IconButton.gif五、ButtonBar 按钮组
ButtonBar 可以默认实现一个按钮组,通过 children 属性可以传入多个 Button,说白了 ButtonBar 就是一个容器,可以统一管理子元素的位置信息。
构造函数:
const ButtonBar({
Key key,
this.alignment = MainAxisAlignment.end,
this.mainAxisSize = MainAxisSize.max,
this.children = const <Widget>[],
}) : super(key: key);
实践运用:
ButtonBar(
alignment:MainAxisAlignment.center ,
children: <Widget>[
RaisedButton(
color: Colors.pink,
textColor: Colors.white,
child: Text('按钮组'),
onPressed: () {},
),
FlatButton(
color: Colors.pink,
textColor: Colors.white,
child: Text('按钮组'),
onPressed: () {},
)
],
)
效果如下:
ButtonBar.png六、FloatingActionButton 悬浮按钮
FloatingActionButton 可以实现浮动按钮,使用场景也是非常多 如:各种购物商场的 返回顶部按钮。
常用属性:
属性名称 属性值
child 子视图,一般为 Icon
tooltip FAB 被长按时显示,也是无障碍功能
backgroundColor 背景颜色
foregroundColor 前景色
elevation 未点击的时候的阴影
hignlightElevation 点击时阴影值,默认 12.0
onPressed 点击事件回调
shape 可以定义 FAB 的形状等
mini 是否是 mini 类型默认 false
heroTag hero效果使用的tag,系统默认会给所有FAB使用同一个tag,方便做动画效果
isExtended 是否为”extended”类型
简单运用:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
HomePageState createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
void handlerDrawerButton() {
}
@override
Widget build(BuildContext context) {
return Scaffold(
//FloatingActionButton
floatingActionButton: FloatingActionButton(
elevation: 0,
backgroundColor: Colors.green,
foregroundColor: Colors.purpleAccent,
child: Icon(
Icons.build,
size: 30,
color: Colors.white,
),
onPressed: () {},
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
backgroundColor: Colors.blue,
body: Container(
child: Center(
child: Text("主页"),
),
),
);
}
}
效果如下绿色悬浮按钮:
FAB.pngFloatingActionButton 的不同类型
FAB 分为三种类型:常规, mini, 和 extended。下面来看这三种有什么区别:
FAB对比.png可以看出 设置mini
时,FAB按钮变小了。使用FloatingActionButton.extended
构造函数可以实现图文并茂的悬浮按钮。
FloatingActionButton 的位置选择
Scaffold Widget中有一个 floatingActionButtonLocation
属性 结合FAB使用,可以指定悬浮按钮的摆放位置。
目前提供了 7 种位置可以选择,在使用时可以分别试试不同的位置效果吧。
七、模仿闲鱼底部导航效果:
为什么要模仿闲鱼? 因为他牛逼啊,哈哈。毕竟别人是国内 Flutter 最大的团队!!!
闲鱼的底部菜单按钮是这样子的:
闲鱼.png结合上面学到的按钮组件 FloatingActionButton 其实我们可以很轻松实现闲鱼效果。我们的案例中已经有创建好的底部菜单,那就充分利用起来吧,进入我们之前写 Tabs.dart 中,在 Scaffold 配置 floatingActionButton 属性,之前没有跟着我写的同学,可以在文末去翻阅源码。
floatingActionButton:Container(
height: 80,
width: 80,
//实现一个圆形
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40),
color: Colors.white,
),
//距离上边 10个单位
margin: EdgeInsets.only(top:10),
// 8个单位的内边距,让周边有浮出感
padding: EdgeInsets.all(8),
child: FloatingActionButton(
child: Icon(Icons.add),
backgroundColor: this._currentIndex==1?Colors.red:Colors.deepPurple,
onPressed: (){
setState(() {
this._currentIndex=1;
});
},
),
),
//指定显示位置
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
最终效果如下:
实战闲鱼.gif非常轻松的就实现了,没什么难度。O(∩_∩)O哈哈~
下面贴出本章中的全部实例图,看图回忆下本章知识点吧!
按钮实例图.png好了本章节到此结束,又到了说再见的时候了,如果你喜欢请留下你的小红星,你们的支持才是创作的动力,如有错误,请热心的你留言指正, 谢谢大家观看,下章再会 O(∩_∩)O
网友评论