一、文本组件-Text
1.1 Text
用于显示文本,控制文本的显示样式,下边几个例子
Text('hello flutter'),
Text(
'hello flutter',
textAlign: TextAlign.left,
),
Text(
'Hello Flutter i am tom' * 4,
overflow: TextOverflow.ellipsis,
),
Text(
'Hello Flutter',
textScaler: TextScaler.linear(1.5),
),
Text(
'Hello Flutter',
style: TextStyle(
fontSize: 30,
),
),
textAlign控制文本位置 left/right/centermaxLines、overflow控制文本超出时显示方式style控制文本:大小、颜色、字体 等
1.2 TextSpan
Text组件内的文本只能一种样式如果想多种样式,就得用TextSpan,当然你也可以text里边嵌套text,看你的使用场景
Text.rich(TextSpan(children: [
TextSpan(text: "Home: "),
TextSpan(
text: "https://flutterchina.club",
style: TextStyle(color: Colors.blue),
recognizer: null),
]))
二、按钮组件-Button
Material 组件库中提供了多种按钮组件如ElevatedButton、TextButton、OutlinedButton,所有 Material 库中的按钮都有如下相同点:
- 按下时都会有“水波动画”(又称“涟漪动画”,就是点击时按钮上会出现水波扩散的动画)。
- 有一个
onPressed属性来设置点击回调,当按钮按下时会执行该回调,如果不提供该回调则按钮会处于禁用状态,禁用状态不响应用户点击。
2.1 ElevatedButton 悬浮按钮
默认有个灰色背景以及边框
2.2 TextButton 文本按钮
2.3 OutlinedButton
带边框背景透明
2.4 IconButton
2.5 带图标的按钮
ElevatedButton、TextButton、OutlinedButton都有一个icon 构造函数,通过它可以轻松创建带图标的按钮
ElevatedButton(onPressed:_onPressed,child: Text("ElevatedButton")),
TextButton(onPressed: _onPressed, child: Text("TextButton")),
OutlinedButton(onPressed: _onPressed, child: Text("OutlinedButton")),
IconButton(onPressed: _onPressed, icon: Icon(Icons.thumb_up)),
ElevatedButton.icon(
onPressed: _onPressed,
icon: Icon(Icons.send),
label: Text("发送"),
),
三、图片组件-Image 图标-Icon
3.1 加载本地图片
- 在工程根目录下创建一个
images目录,并将图片 avatar.png 拷贝到该目录。 - 在
pubspec.yaml中的flutter部分添加如下内容:
assets:
- images/avatar.png
注意: 由于 yaml 文件对缩进严格,所以必须严格按照每一层两个空格的方式进行缩进,此处 assets 前面应有两个空格。
- 加载该文件
Image.network('images/avatar.png', width: 100.0),
3.2 加载网络图片
Image.network(src)
可以设置加载图片的 宽、高、对齐方式、重复方式等
3.3 使用图标
Flutter默认包含了一套Material Design的字体图标,在pubspec.yaml文件中的配置如下
flutter:
uses-material-design: true
使用图标Icon(Icons.business)
官网图标可以在这里查询
使用自定义图标
我们也可以使用自定义字体图标。iconfont.cn上有很多字体图标素材,我们可以选择自己需要的图标打包下载后,会生成一些不同格式的字体文件,在Flutter中,我们使用ttf格式即可。
fonts:
- family: myIcon #指定一个字体名
fonts:
- asset: fonts/iconfont.ttf
注意缩进
为了使用方便,我们定义一个MyIcons类,功能和Icons类一样:将字体文件中的所有图标都定义成静态变量:
class MyIcons{
// book 图标
static const IconData book = const IconData(
0xe614,
fontFamily: 'myIcon',
matchTextDirection: true
);
// 微信图标
static const IconData wechat = const IconData(
0xec7d,
fontFamily: 'myIcon',
matchTextDirection: true
);
}
使用图标
Icon(MyIcons.book,color: Colors.purple),
Icon(MyIcons.wechat,color: Colors.green),
四、单选-Radio 复选-Checkbox
Material 组件库中提供了 Material 风格的单选开关Switch和复选框Checkbox,虽然它们都是继承自StatefulWidget,但它们本身不会保存当前选中状态,选中状态都是由父组件来管理的。当Switch或Checkbox被点击时,会触发它们的onChanged回调,我们可以在此回调中处理选中状态改变逻辑。下面看一个简单的例子:
import 'package:flutter/material.dart';
class MyView extends StatefulWidget {
const MyView({super.key});
@override
State<MyView> createState() => _MyViewState();
}
class _MyViewState extends State<MyView> {
bool _switchCheck = false;
bool _checkboxCheck = false;
@override
Widget build(BuildContext context) {
return Column(
children: [
Switch(
value: _switchCheck,
onChanged: (value) {
setState(() {
_switchCheck = value;
print(_switchCheck);
});
},
),
Checkbox(
value: _checkboxCheck,
onChanged: (value) {
setState(() {
_checkboxCheck = value ?? false;
print(_checkboxCheck);
});
},
),
],
);
}
}
这里注意一个事情,在dart语言中bool类型的值可以被定义成?,也就是null,那么就有三种状态true、false和null,checkbox的返回值value就是这种情况,所以要处理下,它有个参数tristate,就是用来设置是否有三种状态,默认是false,activeColor可以设置激活时颜色
四、输入组件-TextField 表单组件-Form
4.1、TextField TextFormField
习惯了双向数据绑定,其实写flutter还是感觉挺麻烦的。下边是第一种获取输入框的值
class _MyViewState extends State<MyView> {
String _name = '';
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
onChanged: (value) {
setState(() {
_name = value;
print(_name);
});
},
decoration: InputDecoration(
labelText: 'Name',
hintText: 'Enter your name',
prefixIcon: Icon(Icons.person),
)),
],
);
}
}
第二种通过TextEditingController创建,并监听值变化,这种方式较第一种功能稍强大些,可以自定义设置很多属性
class _MyViewState extends State<MyView> {
final TextEditingController _controller = TextEditingController();
@override
void initState() {
_controller.text = 'Hello';
_controller.addListener(() {
print(_controller.text);
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: _controller,
decoration: InputDecoration(
labelText: 'Name',
hintText: 'Enter your name',
prefixIcon: Icon(Icons.person),
)
),
],
);
}
}
关于它的属性有很多下边列举几个常用的
controller:编辑框的控制器,通过它可以设置/获取编辑框的内容、选择编辑内容、监听编辑文本改变事件。大多数情况下我们都需要显式提供一个controller来与文本框交互。如果没有提供controller,则TextField内部会自动创建一个。focusNode:用于控制TextField是否占有当前键盘的输入焦点。它是我们和键盘交互的一个句柄(handle)。InputDecoration:用于控制TextField的外观显示,如提示文本、背景颜色、边框等。keyboardType:用于设置该输入框默认的键盘输入类型,取值如下:
| TextInputType枚举值 | 含义 |
|---|---|
| text | 文本输入键盘 |
| multiline | 多行文本,需和maxLines配合使用(设为null或大于1) |
| number | 数字;会弹出数字键盘 |
| phone | 优化后的电话号码输入键盘;会弹出数字键盘并显示“* #” |
| datetime | 优化后的日期输入键盘;Android上会显示“: -” |
| emailAddress | 优化后的电子邮件地址;会显示“@ .” |
| url | 优化后的url输入键盘; 会显示“/ .” |
textInputAction:键盘动作按钮图标(即回车键位图标),它是一个枚举值,有多个可选值,全部的取值列表读者可以查看API文档 |
style:正在编辑的文本样式。textAlign: 输入框内编辑文本在水平方向的对齐方式。autofocus: 是否自动获取焦点。obscureText:是否隐藏正在编辑的文本,如用于输入密码的场景等,文本内容会用“•”替换。maxLines:输入框的最大行数,默认为1;如果为null,则无行数限制。maxLength和maxLengthEnforcement:maxLength代表输入框文本的最大长度,设置后输入框右下角会显示输入的文本计数。maxLengthEnforcement决定当输入文本长度超过maxLength时如何处理,如截断、超出等。toolbarOptions:长按或鼠标右击时出现的菜单,包括 copy、cut、paste 以及 selectAll。onChange:输入框内容改变时的回调函数;注:内容改变事件也可以通过controller来监听。onEditingComplete和onSubmitted:这两个回调都是在输入框输入完成时触发,比如按了键盘的完成键(对号图标)或搜索键(🔍图标)。不同的是两个回调签名不同,onSubmitted回调是ValueChanged<String>类型,它接收当前输入内容做为参数,而onEditingComplete不接收参数。inputFormatters:用于指定输入格式;当用户输入内容改变时,会根据指定的格式来校验。enable:如果为false,则输入框会被禁用,禁用状态不能响应输入和事件,同时显示禁用态样式(在其decoration中定义)。cursorWidth、cursorRadius和cursorColor:这三个属性是用于自定义输入框光标宽度、圆角和颜色的。
4.2、表单验证
Form组件,需要设置一个key,验证时用来拿到form表单元素,同时TextFormField要添加validator属性,下边是个例子
class _MyViewState extends State<MyView> {
String _name = '';
final GlobalKey _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(
labelText: 'Name',
),
onChanged: (value) {
setState(() {
_name = value;
});
},
validator: (value) {
return value!.trim().length > 5 ? null : 'Name is required';
},
),
ElevatedButton(
onPressed: () {
// if ((_formKey.currentState as FormState).validate()) {
// //验证通过提交数据
// } else {}
final snackBar = SnackBar(
content: const Text('Yay! A SnackBar!'),
);
// Find the ScaffoldMessenger in the widget tree
// and use it to show a SnackBar.
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
child: Text('Submit'),
),
],
));
}
}