在Flutter中,常见的表单组件有TextField单行文本框、TextField多行文本框、CheckBox、Radio、Switch、CheckBoxListTile、RadioListTile、SwitchListTile、Slide等。
下面我将一一为大家做介绍。
TextField
TextField有如下常见属性:
首先我们来看一下TextField的基本用法:
Column(
children: <Widget>[
SizedBox(height: 10),
TextField(
decoration: InputDecoration(
hintText: "请输入搜索内容(这是占位文字)", //占位文字
border: OutlineInputBorder(), //输入框的边框
),
),
SizedBox(height: 10),
TextField(
maxLines: 3, //设置此参数可以将文本框改为多行文本框
decoration: InputDecoration(
labelText: "多行文本框",
border: OutlineInputBorder(),
),
),
SizedBox(height: 10),
TextField(
obscureText: true, //把文本框框改为密码框
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: "密码框labeltext",//配置了该属性,就会呈现一个特殊的效果,可以见示意图
icon: Icon(Icons.people),//在文本框前面配置图标
),
),
],
)
效果如下:
然后我们考虑,如何给输入框中的文字赋初始值呢?这时就要用到controller了。代码如下:
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//第1步,声明TextField的控制器
var _usernameController = TextEditingController();
@override
void initState() {
super.initState();
//第2步,在这里给输入框赋初始值
_usernameController.text = "这是输入框中的初始值";
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: "用户名"
),
//第3步,给TextField绑定controller
controller: _usernameController,
)
],
),
);
}
}
效果如下:
那么如何获取TextField中输入的内容呢?
其实很简单,我们接着上面的代码,只需要通过 _usernameController.text 就可以获取到对应的输入框中的文字了。下面是点击按钮获取输入框中文字的代码:
RaisedButton(
onPressed: (){
print(_usernameController.text);
},
child: Text("获取输入框中的文字"),
)
我们再想一下,如何通过不使用配置controller来获取到输入框中的文字呢?我们可以通过配置 TextField 的 onChanged 回调来监听输入框中文字的实时变化:
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//第1步,声明一个属性,记录输入框中文字
String _usernameStr = "";
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
TextField(
//第2步,实时监听输入框中文字的改变
onChanged: (textValue) {
_usernameStr = textValue;
},
decoration:
InputDecoration(border: OutlineInputBorder(), labelText: "用户名"),
),
SizedBox(height: 20),
Container(
width: double.infinity, //宽度自适应
child: RaisedButton(
onPressed: () {
//第3步,获取输入框中文字
print(_usernameStr);
},
child: Text("获取输入框中的文字"),
),
)
],
),
);
}
}
实际上,上面提到的配置TextField的controller,主要是为了给输入框中的文字赋初始值。如果是单纯地只想获取输入框中文字的话,我们可以另外定义一个变量,然后通过配置TextField的onChanged回调来监听文字的变化。
Checkbox、CheckboxListTile
Checkbox的常用属性如下:
使用代码如下:
class _HomePageState extends State<HomePage> {
bool _flag = true;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
Checkbox(
value: this._flag,//配置选中与否的值
//监听选中状态的改变
onChanged: (value){
setState(() {
this._flag = value;
});
},
//选中时的背景颜色
activeColor: Colors.pink,
//选中时Checkbox里面对号的颜色
checkColor: Colors.yellow,
),
Text(this._flag?"选中":"未选中"),
],
),
);
}
}
效果如下:
Checkbox作为一个选中组件,仅仅提供了选中与否的最基本的视觉展示,如果想要扩展其他的内容,则需要自己去组装。Flutter为我们考虑到了这一点,所以给我们提供了CheckboxListTile组件。
CheckboxListTile组件的属性如下:
代码如下:
Column(
children: <Widget>[
CheckboxListTile(
value: this._flag,//配置选中与否的值
//监听选中状态的改变
onChanged: (value){
setState(() {
this._flag = value;
});
},
//选中时的背景颜色
activeColor: Colors.pink,
//一级标题
title: Text("一级标题"),
//二级标题
subtitle: Text("二级标题"),
//配置图标或者图片
secondary: Icon(Icons.home),
//选中的时候,文字图标等的颜色是否都跟着改变
selected: this._flag,
),
],
)
效果如下:
Radio、RadioListTile
我们可以使用Checkbox来实现多选按钮组的视觉效果,如果想要实现单选按钮组的效果,可以使用Radio。
Radio的常见属性如下:
使用代码如下:
class _HomePageState extends State<HomePage> {
int _sex = 1;//默认选中男
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text("男"),
Radio(
//单选的值
value: 1,
//选中的时候回调
onChanged: (value) {
setState(() {
this._sex = value;
});
},
//配置单选按钮组的选中值,所有该属性值相等的Radio都处于同一个按钮组下
groupValue: this._sex,
),
SizedBox(width: 20),
Text("女"),
Radio(
value: 2,
onChanged: (value) {
setState(() {
this._sex = value;
});
},
groupValue: this._sex,
)
],
),
Row(
children: <Widget>[
Text(this._sex==1?"男":"女"),
],
)
],
),
);
}
}
运行效果如下:
关于上面的代码,这里再啰嗦几句。Radio可以用于实现单选按钮组,有三个属性是必须要配置的:value、onChanged、groupValue。如果某几个 Radio 的 groupValue 属性值配置相同,那么说明这几个Radio处于同一个单选按钮组。
与Checkbox一样,Radio也是仅仅提供了最基本的选中视觉效果,如果想要丰富其他视觉内容的展现,我们需要自己去组装组件。Flutter考虑到这一点,所以为我们提供了一个RadioListTile组件。
RadioListTile组件的属性如下:
使用代码如下:
class _HomePageState extends State<HomePage> {
int _sex = 1; //默认选中男
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
RadioListTile(
value: 1,//配置单选值
groupValue: this._sex,//按钮组的值,该值相同说明在同一个按钮组下
onChanged: (value) {//选中时候的回调
setState(() {
this._sex = value;
});
},
title: Text("男"),//标题
subtitle: Text("男的,雄性的"),//二级标题
secondary: Icon(Icons.headset),//图标或者图片
activeColor: Colors.red,//选中时的背景颜色
selected: this._sex == 1,//选中的时候文字的颜色是否跟着改变为activeColor
),
RadioListTile(
value: 2,
groupValue: this._sex,
onChanged: (value) {
setState(() {
this._sex = value;
});
},
title: Text("女"),
subtitle: Text("女的,雌性的"),
secondary: Icon(Icons.pregnant_woman),
activeColor: Colors.red,
selected: this._sex == 2,
),
RadioListTile(
value: 3,
groupValue: this._sex,
onChanged: (value) {
setState(() {
this._sex = value;
});
},
title: Text("第三性别"),
subtitle: Text("既不是男性,也不是女性"),
secondary: Icon(Icons.tap_and_play),
activeColor: Colors.red,
selected: this._sex == 3,
)
],
),
);
}
}
效果如下:
关于RadioListTile,有一点需要注意:
所有的ListTile(ListTile、CheckboxListTile、RadioListTile)都是竖直排列的,所以要放在竖直排列的组件(比如ListView、Column等)中,不能放在Row这样的水平排列的组件中。
Switch开关
Switch是一个开关组件,常见属性如下:
使用代码如下:
Switch(
value: this._flag,
onChanged: (value){
setState(() {
this._flag = value;
});
},
)
效果图如下:
实例
上面,我依次为大家讲述了TextField、Checkbox、CheckboxListTile、Radio、RadioListTile、Switch等表单组件。接下来,我将把这些表单组件组合起来,通过一个实例给大家更直观地展示一下这些组件的使用场景。
代码如下:
import 'package:flutter/material.dart';
class InfomationNewPage extends StatefulWidget {
InfomationNewPage({Key key}) : super(key: key);
_InfomationNewPageState createState() => _InfomationNewPageState();
}
class _InfomationNewPageState extends State<InfomationNewPage> {
//用户姓名
String _userName;
//性别
int _sex;
//备注信息
String _noteInfo;
//兴趣爱好
List _hobbies = [
{"hobby": "吃饭", "selected": false},
{"hobby": "睡觉", "selected": false},
{"hobby": "喝水", "selected": false},
{"hobby": "爬山", "selected": false},
{"hobby": "攀岩", "selected": false},
{"hobby": "潜水", "selected": false}
];
//获取兴趣爱好组件组(多选组)
List<Widget> _getHobbyWidgets() {
List<Widget> hobbyWidgets = List();
for (var i = 0; i < this._hobbies.length; i++) {
Map map = this._hobbies[i];
hobbyWidgets.add(CheckboxListTile(
value: map["selected"],
title: Text(map["hobby"]),
onChanged: (v) {
setState(() {
this._hobbies[i]["selected"] = v;
});
},
));
}
return hobbyWidgets;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("信息登记系统")),
body: Padding(
padding: EdgeInsets.all(10),
child: ListView(
children: <Widget>[
//姓名(单行输入框)
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(), labelText: "用户姓名"),
onChanged: (text) {
setState(() {
this._userName = text;
});
},
),
//性别(单选按钮组)
Row(
children: <Widget>[
Text("男"),
Radio(
value: 1,
onChanged: (sex) {
setState(() {
this._sex = sex;
});
},
groupValue: this._sex,
),
SizedBox(width: 20),
Text("女"),
Radio(
value: 2,
onChanged: (sex) {
setState(() {
this._sex = sex;
});
},
groupValue: this._sex,
)
],
),
//兴趣爱好(多选按钮组)
Column(
children: this._getHobbyWidgets(),
),
//备注信息(多行输入框)
TextField(
maxLines: 4,
decoration: InputDecoration(
hintText: "请输入备注信息",
border: OutlineInputBorder(),
),
onChanged: (v) {
setState(() {
this._noteInfo = v;
});
},
),
SizedBox(height: 20),
//提交按钮(获取各种表单的信息)
RaisedButton(
color: Colors.blue,
child: Text("提交"),
onPressed: () {
FocusScope.of(context).requestFocus(FocusNode());
print("""
------
用户姓名:${this._userName},
性别:${this._sex}, ${this._sex == 1 ? "男" : "女"},
兴趣爱好:${this._hobbies},
备注信息:${this._noteInfo}
""");
},
)
],
),
),
);
}
}
效果如下:
以上。