一、Button Widget
按钮是开发中常用的可与用户交互的组件,在 Flutter 中,提供了很多跟按钮相关的 Widget 。
1. MaterialButton
MaterialButton
是用来构建一个依赖于 ButtomTheme
和 Theme
的实用工具类。其实现了按钮的基本需求功能,但是官方不建议直接使用此类来创建按钮,此类多用于定时和按钮 Widget 的基类。 应该尽量使用其提供的三个子类来创建,三个子类分别为:RaisedButton
、FlatButton
、OutlineButton
。这三个子类实现了 Material Design 设计风格的默认参数设置。MaterialButton
继承自 StatelessWidget
,为无状态 Widget, 其构造方法如下:
const MaterialButton({
Key key,
//Function类型必传参数,为当按钮点击时的回调方法,如果为null,按钮将处于禁用状态
@required this.onPressed,
//Function类型可选命名参数,为当长按按钮时的回调方法
this.onLongPress,
//Function类型可选命名参数,为当按钮突出(高亮)显示或停止突出显示时调用的回调方法,参数bool类型
this.onHighlightChanged,
//ButtonTextTheme类型可选命名参数,用来定义按钮的基本颜色,最小尺寸,内部填充和形状的默认值
this.textTheme,
//Color类型可选命名参数,为按钮文本的颜色
this.textColor,
//Color类型可选命名参数,为按钮禁用时的按钮文本的颜色
this.disabledTextColor,
//Color类型可选命名参数,按钮状态为可用时且未被点击时的填充色
this.color,
//Color类型可选命名参数,为按钮禁用时的按钮填充颜色
this.disabledColor,
//Color类型可选命名参数,当按钮具有输入焦点时的填充颜色
this.focusColor,
//Color类型可选命名参数,指针悬停在按钮上时的填充颜色
this.hoverColor,
//Color类型可选命名参数,用于设置按钮的高亮颜色
this.highlightColor,
//Color类型可选命名参数,按钮点击时水波纹效果的颜色
this.splashColor,
//Brightness类型可选命名参数,用于设置按钮的主题亮度
this.colorBrightness,
//double类型可选命名参数,相对于其父级放置此按钮的z坐标,可用于控制凸起按钮下方的
//阴影大小,默认值为2,不能为负数
this.elevation,
//double类型可选命名参数,当按钮启用并具有焦点时,按钮的elevation
this.focusElevation,
//double类型可选命名参数,当按钮启用且指针悬停在按钮上方时,按钮的按钮的elevation
this.hoverElevation,
//double类型可选命名参数,按钮为启用状态并被按下时其相对于父级的高程
this.highlightElevation,
//double类型可选命名参数,当按钮为不可用状态时其相对于父级的高程
this.disabledElevation,
//EdgeInsetsGeometry类型可选命名参数,设置按钮的内边距
this.padding,
//ShapeBorder类型可选命名参数,设置按钮形状
this.shape,
//Clip类型可选命名参数,用于设置内容将被如何裁剪
this.clipBehavior = Clip.none,
//FocusNode类型可选命名参数,按钮的焦点节点
this.focusNode,
//bool类型可选命名命名参数,用于设置是否按钮为当前焦点
this.autofocus = false,
//MaterialTapTargetSize类型可选命名参数,设置按钮的最小点击尺寸
this.materialTapTargetSize,
//Duration类型可选命名参数,用于定义按钮形状或高亮变化的动画的持续时间
this.animationDuration
//double类型可选命名参数,按钮的最小宽度
this.minWidth,
//double类型可选命名参数,按钮的高度
this.height,
//bool类型可选命名参数,当检测到手势时,是否提供听觉视觉的反馈
this.enableFeedback = true,
//Widget类型可选命名参数,是为按钮设置的显示标签,可以为任意Widget,通常使用Text
this.child,
})
基本使用如下:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Widget基础"),
),
body: studyWidget(context),
),
);
}
}
//示例代码值修改此函数
Widget studyWidget(BuildContext context) {
return MaterialButton(
child: Text("MaterialButton"),
onPressed: ()=> print("按钮被点击"),
color: Colors.red, //不设置填充色默认为无色
);
}
2. RaisedButton Widget
RaisedButton
是一种外观凸起的按钮,其最小尺寸为 88.0 * 36.0 。构造函数如下:
const RaisedButton({
Key key,
@required VoidCallback onPressed,
VoidCallback onLongPress,
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 = Clip.none,
FocusNode focusNode,
bool autofocus = false,
MaterialTapTargetSize materialTapTargetSize,
Duration animationDuration,
Widget child,
})
参数与 MaterialButton
相同部分不再介绍。使用方式如下:
//示例代码值修改此函数
Widget studyWidget(BuildContext context) {
return RaisedButton(
child: Text("RaisedButton"),
onPressed: ()=> print("按钮被点击"),
);
}
也可写做如下形式:
//示例代码值修改此函数
Widget studyWidget(BuildContext context) {
return RaisedButton(
child: Text("RaisedButton"),
onPressed: buttonPressed,
);
}
void buttonPressed() {
print("按钮被点击");
}
其默认效果如下:
其他属性如下,使用纵向布局 Widget Column
来展示,如下:
Widget studyWidget(BuildContext context) {
return Column(
children: <Widget>[
RaisedButton(
child: Text("RaisedButton1"),
color: Colors.red, //按钮填充色
textColor: Colors.amber, //文字颜色
onPressed: ()=> print("按钮被点击"),
),
RaisedButton(
child: Text("RaisedButton2"),
onPressed: ()=> print("按钮被点击"),
textTheme: ButtonTextTheme.primary, //按钮主题
),
RaisedButton(
child: Text("RaisedButton3"),
disabledColor: Colors.blue, //按钮禁用时的填充色
),
RaisedButton(
child: Text("RaisedButton4"),
disabledTextColor: Colors.tealAccent, //按钮禁用时的文字颜色
),
RaisedButton(
child: Text("RaisedButton5"),
onPressed: ()=> print("按钮被点击"),
padding: EdgeInsets.all(20.0), //设备按钮内边距
),
RaisedButton(
child: Text("RaisedButton6"),
onPressed: ()=> print("按钮被点击"),
shape: BeveledRectangleBorder( //设置按钮形状
borderRadius: BorderRadius.circular(8),
),
),
],
);
}
效果如下图:
ButtonTextTheme
是一个枚举类型,如下:
enum ButtonTextTheme {
//按钮文本的颜色是黑还是白取决于主题 [ThemeData.brightness]
normal,
//按钮文本的颜色与[ThemeData.accentColor]相同
accent,
//按钮文本的颜色依赖于[ThemeData.accentColor]
primary,
}
在设置内边距 padding
使用的是 EdgeInsetsGeometry
,EdgeInsetsGeometry
是一个抽象类,其有两个子类 EdgeInsets
和 EdgeInsetsDirectional
,这里使用 EdgeInsets
,其构造函数如下:
//通过左、上、右、底来创建边距
EdgeInsets.fromLTRB(this.left, this.top, this.right, this.bottom);
//四周创建同样距离的边距
EdgeInsets.all(double value) : left = value, top = value, right = value, bottom = value;
//可以单独为某个方向创建边距
EdgeInsets.only({
this.left = 0.0,
this.top = 0.0,
this.right = 0.0,
this.bottom = 0.0,
});
//纵向和横向边距
EdgeInsets.symmetric({
double vertical = 0.0,
double horizontal = 0.0,
}) : left = horizontal,
top = vertical,
right = horizontal,
bottom = vertical;
//创建于指定窗口边距相同的边距
EdgeInsets.fromWindowPadding(ui.WindowPadding padding, double devicePixelRatio)
: left = padding.left / devicePixelRatio,
top = padding.top / devicePixelRatio,
right = padding.right / devicePixelRatio,
bottom = padding.bottom / devicePixelRatio;
shape
设置形状使用的是 ShapeBorder
,其也是一个抽象类,这里使用的是其子类,如下:
BeveledRectangleBorder
用于创建带有平角或斜角的矩形边框。构造函数如下:
const BeveledRectangleBorder({
//BorderSide类型参数,为边框样式
this.side = BorderSide.none,
//BorderRadiusGeometry类型命名可选参数,为每个角的半径
this.borderRadius = BorderRadius.zero,
})
除此之外还有很多其他的形状类可以使用。
3. FlatButton Widget
FlatButton
是平面按钮,没有凸起与阴影等效果,如果不设置颜色等只能看见文字(设置文字的情况下)。使用方式与上述相同。
4. OutlineButton Widget
OutlineButton
为带边框的按钮,其构造函数如下:
const OutlineButton({
Key key,
@required VoidCallback onPressed,
//BorderSide类型可选命名参数,为在按钮可用且未点击状态的边框样式
this.borderSide,
//Color类型可选命名参数,为按钮不可用状态时的边框颜色
this.disabledBorderColor,
//Color类型可选命名参数,为按钮可用状态并按下时边框的颜色
this.highlightedBorderColor,
//.... 省略相同属性部分
Widget child,
})
使用方式与上述相同。
上面介绍的是 MaterialButton
与其子类按钮,下面介绍其他的功能按钮。
5. FloatingActionButton Widget
FloatingActionButton
为 Material Design 设计风格的浮动按钮,可悬停在内容之上,以提升应用程序的主要操作。每个屏幕最多使用一个浮动按钮。其继承自 StatelessWidget
为无状态按钮,有两个构造函数如下:
FloatingActionButton()
构造函数,用于创建圆形浮动操作按钮。
const FloatingActionButton({
Key key,
//Widget类型可选命名参数,是为按钮设置的显示的Widget
this.child,
//String类型可选命名参数,按钮按下时弹出的提示文本
this.tooltip,
//Color类型可选命名参数,默认图标和文本颜色
this.foregroundColor,
//Color类型可选命名参数,按钮的背景填充色
this.backgroundColor,
//Color类型可选命名参数,当按钮具有输入焦点时用于填充按钮的颜色
this.focusColor,
//Color类型可选命名参数,指针悬停在按钮上时的填充颜色
this.hoverColor,
//Color类型可选命名参数,按钮点击时水波纹效果的颜色
this.splashColor,
//Object类型可选命名参数,应用于按钮的“英雄”小部件的标签
this.heroTag = const _DefaultHeroTag(),
//double类型可选命名参数,相对于其父按钮放置此按钮的z坐标
this.elevation,
//double类型可选命名参数,当按钮具有输入焦点时,相对于其父按钮放置该按钮的z坐标
this.focusElevation,
//double类型可选命名参数,当按钮启用且指针悬停在按钮上方时,按钮的按钮的elevation
this.hoverElevation,
//double类型可选命名参数,按钮为启用状态并被按下时其相对于父级的高程
this.highlightElevation,
//double类型可选命名参数,按钮禁用时放置该按钮的z坐标
this.disabledElevation,
//Function类型必传参数,为当按钮点击时的回调方法,如果为null,按钮将处于禁用状态
@required this.onPressed,
//bool类型可选命名参数,控制此按钮的大小
this.mini = false,
//ShapeBorder类型可选命名参数,设置按钮形状
this.shape,
//Clip类型可选命名参数,用于设置内容将被如何裁剪
this.clipBehavior = Clip.none,
//FocusNode类型可选命名参数,此小部件的焦点节点
this.focusNode,
//bool类型可选命名参数,如果在当前范围内没有其他节点被聚焦时,此小部件将被选为初始焦点,则为True
this.autofocus = false,
//MaterialTapTargetSize类型可选命名参数,设置按钮的最小点击尺寸
this.materialTapTargetSize,
//bool类型可选命名参数,如果这是“扩展”浮动操作按钮,则为True
this.isExtended = false,
})
使用如下:
Widget studyWidget(BuildContext context) {
return FloatingActionButton(
child: Icon(Icons.print),
foregroundColor: Colors.red,
backgroundColor: Colors.yellow,
onPressed: ()=> print("按钮被点击"),
);
}
效果如下图:
FloatingActionButton.extended()
构造函数,用于创建一个更宽的带有可选图标和标签的边框形状的浮动操作按钮。
FloatingActionButton.extended({
Key key,
//Widget类型可选命名参数,为要实现的图标
Widget icon,
//Widget类型必传参数,为按钮要显示的标签
@required Widget label,
//...省略相同功能的属性
})
使用如下:
Widget studyWidget(BuildContext context) {
return FloatingActionButton.extended(
icon: Icon(Icons.memory),
label: Text("按钮"),
foregroundColor: Colors.red,
backgroundColor: Colors.yellow,
onPressed: ()=> print("按钮被点击"),
);
}
效果如下:
6. IconButton Widget
Material Design 设计风格图标按钮,其继承自 StatelessWidget
为无状态按钮,构造方法如下:
const IconButton({
Key key,
//double类型可选命名参数,用来定义按钮内图标的大小
this.iconSize = 24.0,
//EdgeInsetsGeometry类型可选命名参数,用于定义图标按钮的内边距
this.padding = const EdgeInsets.all(8.0),
//AlignmentGeometry类型可选命名参数,用于设置图标显示的位置
this.alignment = Alignment.center,
//Widget类型必传参数,按钮内部使用的图标
@required this.icon,
//Color类型可选命名参数,按钮处于启动状态时,内部图标使用的颜色
this.color,
//Color类型可选命名参数,当按钮具有输入焦点时,按钮图标的颜色
this.focusColor,
//Color类型可选命名参数,指针悬停在按钮上时的填充颜色
this.hoverColor,
//Color类型可选命名参数,用于设置按钮的高亮颜色
this.highlightColor,
//Color类型可选命名参数,按钮点击时水波纹效果的颜色
this.splashColor,
//Color类型可选类型参数,按钮禁用状态下,内部图标使用的颜色
this.disabledColor,
//Function类型必传参数,为当按钮点击时的回调方法,如果为null,按钮将处于禁用状态
@required this.onPressed,
//FocusNode类型可选命名参数,此小部件的焦点节点
this.focusNode,
//bool类型可选命名参数,如果当其范围内没有其他节点当前被聚焦时,此小部件将被选为初始焦点,则为True
this.autofocus = false,
//String类型可选命名参数,按钮按下时弹出的提示文本
this.tooltip,
//bool类型可选命名参数,检测到的手势是否提供听觉视觉的反馈
this.enableFeedback = true,
})
使用方式如下:
Widget studyWidget(BuildContext context) {
return IconButton(
icon: Icon(Icons.add),
color: Colors.yellow,
onPressed: (){},
);
}
7. DropdownButton Widget
DropdownButton
用于定义一个下拉菜单按钮,每一个菜单项使用 DropdownMenuItem
定义。一个菜单中的菜单项需要为同一类型。DropdownButton
继承自 StatefulWidget
为一个有状态的 Widget ,其构造函数如下:
DropdownButton({
Key key,
// List<DropdownMenuItem<T>>类型必传参数,设置的菜单项列表
@required this.items,
//DropdownButtonBuilder类型可选命名参数,用于定制与项目中的下拉菜单
//项(DropdownMenuItem)相对应的按钮
this.selectedItemBuilder,
//泛型T类型可选命名参数,为当前选择的是哪个下拉菜单项
this.value,
//Widget类型可选命名参数,下拉按钮显示的占位符Widget
this.hint,
//Widget类型可选命名参数,当下拉菜单被禁用时显示的内容
this.disabledHint,
//Function类型必传参数,选择一个菜单项时调用
@required this.onChanged,
//int类型可选命名参数,打开时放置菜单的z坐标
this.elevation = 8,
//TextStyle类型可选命名参数,用于设置下拉菜单中文本的文本的样式,以及点击按钮时出现的下拉菜单
this.style,
//Widget类型可选命名参数,用于绘制下拉按钮下划线的Widget
this.underline,
//Widget类型可选命名参数,下拉按钮图标的Widget
this.icon,
//Color类型可选命名参数,按钮禁用状态的内部图标的颜色
this.iconDisabledColor,
//Color类型可选命名参数,按钮启用状态的内部图标的颜色
this.iconEnabledColor,
//double类型可选命名参数,下拉按钮的向下箭头图标按钮的大小
this.iconSize = 24.0,
//bool类型可选命名参数,是否降低按钮的高度
this.isDense = false,
//bool类型可选命名参数,是否将下拉列表的内部内容设置为水平填充其父项
this.isExpanded = false,
//double类型可选命名参数,如果为null,则菜单项高度将根据每个菜单项的固有高度而变化
this.itemHeight = kMinInteractiveDimension,
//Color类型可选命名参数,当按钮具有输入焦点时,按钮材质的颜色
this.focusColor,
//FocusNode类型可选命名参数,此小部件的焦点节点
this.focusNode,
//bool类型可选命名参数,如果当其范围内没有其他节点当前被聚焦时,此小部件将被选为初始焦点,则为True
this.autofocus = false,
})
DropdownMenuItem
菜单项的构造函数如下:
const DropdownMenuItem({
Key key,
//泛型T类型可选参数,为当用户选择此菜单项时返回的值
this.value,
//Widget类型必传参数,菜单项要显示的Widget
@required Widget child,
})
基本使用方式如下:
Widget studyWidget(BuildContext context) {
return DropdownButton(
items: <DropdownMenuItem<int>>[
DropdownMenuItem(
child: Text("Item 1"),
value: 1,
),
DropdownMenuItem(
child: Text("Item 2"),
value: 2,
),
DropdownMenuItem(
child: Text("Item 3"),
value: 3,
),
],
onChanged: (value)=> print(value),
);
}
但是现在存在一个问题,虽然可以选择菜单项并且输出对应的 value
,但是操作后界面是无变化的。上面说过 DropdownButton
继承自 StatefulWidget
,是一个有状态的 Widget,对于有状态的 Widget ,前面文章曾经介绍过,都会与状态类一起使用,在状态类中对数据界面做操作才能实现界面的更新操作,更改代码如下:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Widget基础"),
),
body: MyDropdownMenu(),
),
);
}
}
class MyDropdownMenu extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _MyDropdownMenuState();
}
}
class _MyDropdownMenuState extends State<MyDropdownMenu> {
int currentSelectIndex = 1;
@override
Widget build(BuildContext context) {
return DropdownButton(
items: <DropdownMenuItem<int>>[
DropdownMenuItem(
child: Text("Item 1"),
value: 1,
),
DropdownMenuItem(
child: Text("Item 2"),
value: 2,
),
DropdownMenuItem(
child: Text("Item 3"),
value: 3,
),
],
value: currentSelectIndex,
onChanged: (value) {
print(value);
setState(() {
currentSelectIndex = value;
});
},
);
}
}
将更新数据项放在 setState()
方法内进行操作即可。
其他属性设置如下:
class _MyDropdownMenuState extends State<MyDropdownMenu> {
int currentSelectIndex = 1;
@override
Widget build(BuildContext context) {
return DropdownButton(
items: <DropdownMenuItem<int>>[
DropdownMenuItem(
child: Text("Item 1"),
value: 1,
),
DropdownMenuItem(
child: Text("Item 2"),
value: 2,
),
DropdownMenuItem(
child: Text("Item 3"),
value: 3,
),
],
value: currentSelectIndex,
selectedItemBuilder: (BuildContext context){
return <Widget>[
Icon(Icons.add),
Icon(Icons.print),
Icon(Icons.ac_unit),
];
},
hint: Text("hint"),
disabledHint: Text("按钮被禁用"),
style: TextStyle(
fontSize: 24.0,
color: Colors.red,
),
underline: Container(
height: 1,
color: Colors.yellow,
),
icon: Icon(Icons.arrow_downward),
onChanged: (value) {
print(value);
setState(() {
currentSelectIndex = value;
});
},
);
}
}
效果如下:
selectedItemBuilder
使用 DropdownButtonBuilder
构造器,其是一个返回 List<Widget>
的 Function
,圆形为:List<Widget> Function(BuildContext context)
,作用是定义与下拉列表中选项相对应的每一个 Widget ,这个 Widget 用来显示在菜单未点开的情况下显示。
hint
用来定义按钮在 value
属性为 null
或此按钮被禁用且 disabledHint
属性也为 null
时显示。
disabledHint
如果不为 null
,在按钮被禁用时显示。
icon
属性用来定义下拉按钮靠右侧显示的图标。
8. PopupMenuButton Widget
PopupMenuButton
是弹出菜单
const PopupMenuButton({
Key key,
//PopupMenuItemBuilder<T>类型必传参数,当按下按钮创建要在菜单中显示的项目时调用
@required this.itemBuilder,
//泛型T类型可选命名参数,菜单打开时应突出显示的菜单项的值(如果有),也就是打开时选择哪一项
this.initialValue,
//PopupMenuItemSelected<T>类型可选命名参数,当用户从该按钮创建的弹出菜单中选择一个值时调用
this.onSelected,
//PopupMenuCanceled类型可选命名参数,当用户在不选择项目的情况下关闭弹出菜单时调用
this.onCanceled,
//String类型可选命名参数,按钮按下时弹出的提示文本
this.tooltip,
//double类型可选命名参数,打开时放置菜单的z坐标。这控制了菜单下阴影的大小
this.elevation,
//EdgeInsetsGeometry类型可选命名参数,默认情况下匹配图标按钮的8 dps填充。在某些情况下,特别是当该按钮作为列表项的尾部元素出现时,能够将填充设置为零是很有用的
this.padding = const EdgeInsets.all(8.0),
//Widget类型可选命名参数,如果提供,child是用于该按钮的小部件,该按钮将利用InkWell进行点击
this.child,
//Widget类型可选命名参数,如果图标用于此按钮,该按钮的行为类似IconButton
this.icon,
//Offset类型可选命名参数,应用于弹出菜单按钮的偏移量
this.offset = Offset.zero,
//bool类型可选命名参数,该弹出菜单按钮是否是交互式的
this.enabled = true,
//ShapeBorder类型可选命名参数,用于菜单的形状
this.shape,
//Color类型可选命名参数,菜单背景颜色
this.color,
//bool类型可选命名参数,如果为真(缺省值),那么菜单将被包装成继承主题的副本,如主题和弹出主题,它们被定义在显示菜单的构建上下文之上
this.captureInheritedThemes = true,
})
itemBuilder
的类型是 PopupMenuItemBuilder<T>
,其是一个 Function
,原型为:List<PopupMenuEntry<T>> Function(BuildContext context)
。PopupMenuButton
的使用如下:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Widget基础"),
),
body: MyPopupMenuButton(),
),
);
}
}
class MyPopupMenuButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return PopupMenuButton(
itemBuilder: (context) {
return <PopupMenuEntry<String>> [
const PopupMenuItem(
child: Text("选项1"),
value: "1",
),
const PopupMenuItem(
child: Text("选项2"),
value: "2",
),
const PopupMenuItem(
child: Text("选项3"),
value: "3",
),
];
},
onSelected: (value){
print(value);
},
onCanceled: (){
print("未选择任何选项,菜单关闭");
},
icon: Icon(Icons.add),
initialValue: "2",
offset: Offset(50, 110),
color: Colors.yellow,
);;
}
}
其中,child
和 icon
只能选择一个使用,都是图标在界面上未展开时显示的 Widget 。这里使用的是无状态的形式,如果需要对界面做数据更新处理,则需要使用 StatefulWidget
。
效果如下: