表单组件
2019-12-20 本文已影响0人
放肆滴微笑
Flutter 中常见的表单有 TextField 单行文本框,TextField 多行文本框、CheckBox、Radio、Switch、CheckboxListTile、RadioListTile、SwitchListTile、Slide
TextField
属性 | 描述 |
---|---|
maxLines | 设置此参数可以把文本框改为多行文本框 |
onChanged | 文本框改变的时候触发的事件 |
obscureText | 把文本框框改为密码框 |
controller | controller 结合 TextEditingController()可以配置表单默认显示的内容,也可以进行赋值 |
decoration | hintText类似 html 中的 placeholder border 配置文本框边框 OutlineInputBorder 配合使用 labelText lable 的名称 labelStyle 配置 lable 的样式 |
const TextField({
Key key,
this.controller, //编辑框的控制器,跟文本框的交互一般都通过该属性完成,如果不创建的话默认会自动创建
this.focusNode, //用于管理焦点
this.decoration = const InputDecoration(), //输入框的装饰器,用来修改外观
TextInputType keyboardType, //设置输入类型,不同的输入类型键盘不一样
this.textInputAction, //用于控制键盘动作(一般位于右下角,默认是完成)
this.textCapitalization = TextCapitalization.none,
this.style, //输入的文本样式
this.textAlign = TextAlign.start, //输入的文本位置
this.textDirection, //输入的文字排列方向,一般不会修改这个属性
this.autofocus = false, //是否自动获取焦点
this.obscureText = false, //是否隐藏输入的文字,一般用在密码输入框中
this.autocorrect = true, //是否自动校验
this.maxLines = 1, //最大行
this.maxLength, //能输入的最大字符个数
this.maxLengthEnforced = true, //配合maxLength一起使用,在达到最大长度时是否阻止输入
this.onChanged, //输入文本发生变化时的回调
this.onEditingComplete, //点击键盘完成按钮时触发的回调,该回调没有参数,(){}
this.onSubmitted, //同样是点击键盘完成按钮时触发的回调,该回调有参数,参数即为当前输入框中的值。(String){}
this.inputFormatters, //对输入文本的校验
this.enabled, //输入框是否可用
this.cursorWidth = 2.0, //光标的宽度
this.cursorRadius, //光标的圆角
this.cursorColor, //光标的颜色
this.keyboardAppearance,
this.scrollPadding = const EdgeInsets.all(20.0),
this.dragStartBehavior = DragStartBehavior.down,
this.enableInteractiveSelection,
this.onTap, //点击输入框时的回调(){}
this.buildCounter,
})
InputDecoration({
this.icon, //位于装饰器外部和输入框前面的图片
this.labelText, //用于描述输入框,例如这个输入框是用来输入用户名还是密码的,当输入框获取焦点时默认会浮动到上方,
this.labelStyle, // 控制labelText的样式,接收一个TextStyle类型的值
this.helperText, //辅助文本,位于输入框下方,如果errorText不为空的话,则helperText不会显示
this.helperStyle, //helperText的样式
this.hintText, //提示文本,位于输入框内部
this.hintStyle, //hintText的样式
this.hintMaxLines, //提示信息最大行数
this.errorText, //错误信息提示
this.errorStyle, //errorText的样式
this.errorMaxLines, //errorText最大行数
this.hasFloatingPlaceholder = true, //labelText是否浮动,默认为true,修改为false则labelText在输入框获取焦点时不会浮动且不显示
this.isDense, //改变输入框是否为密集型,默认为false,修改为true时,图标及间距会变小
this.contentPadding, //内间距
this.prefixIcon, //位于输入框内部起始位置的图标。
this.prefix, //预先填充的Widget,跟prefixText同时只能出现一个
this.prefixText, //预填充的文本,例如手机号前面预先加上区号等
this.prefixStyle, //prefixText的样式
this.suffixIcon, //位于输入框后面的图片,例如一般输入框后面会有个眼睛,控制输入内容是否明文
this.suffix, //位于输入框尾部的控件,同样的不能和suffixText同时使用
this.suffixText,//位于尾部的填充文字
this.suffixStyle, //suffixText的样式
this.counter,//位于输入框右下方的小控件,不能和counterText同时使用
this.counterText,//位于右下方显示的文本,常用于显示输入的字符数量
this.counterStyle, //counterText的样式
this.filled, //如果为true,则输入使用fillColor指定的颜色填充
this.fillColor, //相当于输入框的背景颜色
this.errorBorder, //errorText不为空,输入框没有焦点时要显示的边框
this.focusedBorder, //输入框有焦点时的边框,如果errorText不为空的话,该属性无效
this.focusedErrorBorder, //errorText不为空时,输入框有焦点时的边框
this.disabledBorder, //输入框禁用时显示的边框,如果errorText不为空的话,该属性无效
this.enabledBorder, //输入框可用时显示的边框,如果errorText不为空的话,该属性无效
this.border, //正常情况下的border
this.enabled = true, //输入框是否可用
this.semanticCounterText,
this.alignLabelWithHint,
})
enum TextInputAction {
//没有任何动作
none,
//让操作系统决定哪个动作更合适
unspecified,
//完成动作,一般会显示“完成”二字
done,
/// 跳转动作,一般用于输入了一个超链接后执行该动作。键盘上会显示“前往”二字
go,
//搜索动作
search,
//发送
send,
///下个
next,
/// 返回前一个
previous,
//继续动作,在Android上好像没反应,不显示键盘
continueAction,
//在Android上好像没反应,不显示键盘
route,
//拨打紧急电话,在Android上好像没反应,不显示键盘
emergencyCall,
//换行
newline,
}
TextField onChanged
onChanged: (val) {
print(val);
},
TextField onEditingComplete
onEditingComplete: (){
print("点击了键盘上的动作按钮");
},


@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: EdgeInsets.all(20),
child: ListView(
children: <Widget>[
TextField(
decoration: InputDecoration(
hintText: "请输入用户名",
),
controller: _username,
onChanged: (value) {
setState(() {
_username.text = value;
});
},
),
Divider(),
TextField(
decoration: InputDecoration(icon: Icon(Icons.phone)),
),
Divider(),
TextField(
decoration: InputDecoration(
labelText: "用户名",
labelStyle: TextStyle(color: Colors.red, fontSize: 20)),
),
Divider(),
TextField(
decoration: InputDecoration(
labelText:
"labelText是否浮动,默认为true,修改为false则labelText在输入框获取焦点时不会浮动且不显示",
hasFloatingPlaceholder: false),
),
Divider(),
TextField(
decoration: InputDecoration(
hintText: "hint 文字",
helperText: "请输入邮箱",
errorText: "sss", //如果有errorText ,则helperText不显示
),
),
Divider(),
TextField(
decoration: InputDecoration(
// icon: Icon(Icons.phone),
prefixIcon: Icon(Icons.radio_button_checked),
prefixText: "预填充文字"),
),
Divider(),
TextField(
decoration: InputDecoration(
suffixIcon: Icon(Icons.remove_red_eye),
suffixText: "suffixIcon suffixText"),
),
Divider(),
TextField(
decoration: InputDecoration(counterText: "counterText"),
),
TextField(
decoration: InputDecoration(
filled: true,
fillColor: Colors.cyanAccent,
hintText: "颜色填充"),
),
TextField(
decoration: InputDecoration(
border: InputBorder.none, hintText: "没有边框"),
),
TextField(
decoration: InputDecoration(
hintText: "边框样式",
//未点击后
enabledBorder: OutlineInputBorder(
// 边角
borderRadius: BorderRadius.all(Radius.circular(20)),
borderSide: BorderSide(color: Colors.blue, width: 2)),
// 点击后
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.yellow, width: 2))),
),
TextField(
decoration: InputDecoration(
hintText: "底边线,默认",
errorBorder: UnderlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
borderSide: BorderSide(color: Colors.blue),
),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.green,
//边框颜色为绿色
width: 5, //宽度为5
)),
),
)
],
)));
}
CheckBox
Checkbox({
this.tristate = false, //如果为 true,那么复选框的值可以是 true,false 或 null。
this.onChanged, //ValueChanged - 改变时触发。
this.activeColor, //激活时的颜色。
this.checkColor, //对勾的颜色
this.materialTapTargetSize,
}
CheckboxListTile
属性 | 描述 |
---|---|
value | true 或者 false |
onChanged | 改变的时候触发的事件 |
activeColor | 选中的颜色、背景颜色 |
title | 标题 |
subtitle | 二级标题 |
secondary | 配置图标或者图片 |
selected | 选中的时候文字颜色是否跟着改变 |

body: Container(
child: Column(
children: <Widget>[
Checkbox(
value: select,
onChanged: (v) {
setState(() {
this.select = v;
});
}),
Row(
children: <Widget>[
Checkbox(
checkColor: Colors.cyanAccent,
value: select,
onChanged: (v) {
setState(() {
this.select = v;
});
}),
Text(this.select ? "选中" : "未选中"),
],
),
Divider(),
CheckboxListTile(
value: this.select,
onChanged: (v) {
setState(() {
this.select = v;
});
},
title: Text("这是CheckboxListTile"),
subtitle: Text("这是副标题"),
activeColor: Colors.yellow,
secondary: Icon(Icons.help),
)
],
),
),
Radio
是单选值,所以在一组中只有1个能被选中,groupValue就是这个组,必须每个Radio都要写,而且要一样
Radio
属性 | 描述 |
---|---|
value | 单选的值 |
onChanged | 改变时触发,获得是选中的值 |
activeColor | 选中的颜色、背景颜色 |
groupValue | 选择组的值 |
RadioListTile
属性 | 描述 |
---|---|
value | true 或者 false |
onChanged | 改变的时候触发的事件 |
activeColor | 选中的颜色、背景颜色 |
title | 标题 |
subtitle | 二级标题 |
secondary | 配置图标或者图片 |
groupValue | 选择组的值 |
selected | true false true 则当前高亮显示 |

class _RadioDemoState extends State<RadioDemo> {
int groupValue = 1;
int sex = 1;
bool switchFlag = true;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
Row(
children: <Widget>[
Text("男:"),
Radio(
value: 1,
groupValue: groupValue,
onChanged: (v) {
setState(() {
this.groupValue = v;
});
}),
SizedBox(
width: 10,
),
Text("女:"),
Radio(
value: 2,
groupValue: groupValue,
onChanged: (v) {
setState(() {
this.groupValue = v;
});
},
)
],
),
Row(
children: <Widget>[
Text("${this.groupValue}"),
Text("${this.groupValue == 1 ? "男" : "女"}")
],
),
SizedBox(
height: 50,
),
RadioListTile(
selected: this.groupValue == 1, //true 则当前高亮显示
title: Text("tilte"),
subtitle: Text("subtitle"),
secondary: Icon(Icons.phone),
value: 1,
groupValue: this.groupValue,
onChanged: (v) {
setState(() {
this.groupValue = v;
});
},
),
RadioListTile(
selected: this.groupValue == 2, //true 则当前高亮显示
title: Text("tilte"),
subtitle: Text("subtitle"),
secondary: Icon(Icons.phone),
value: 2,
groupValue: this.groupValue, // 和上面是一个组的
onChanged: (v) {
setState(() {
this.groupValue = v;
});
},
),
Switch(value: switchFlag, onChanged: (v){
setState(() {
this.switchFlag = v;
});
})
],
),
),
);
}
}
表单提交

class _FromDemoState extends State<FromDemo> {
String username;
int sex = 1;
String result="";
List hobby = [
{"checked": true, "title": "吃饭"},
{"checked": true, "title": "跑步"},
{"checked": true, "title": "打麻将"}
];
List<Widget> getHobby() {
List<Widget> tmp = [];
for (var i = 0; i < hobby.length; i++) {
tmp.add(Row(
children: <Widget>[
Text(hobby[i]["title"]),
Checkbox(
value: hobby[i]["checked"],
onChanged: (v) {
setState(() {
hobby[i]["checked"] = v;
});
})
],
));
}
return tmp;
}
void _sexChange(value) {
setState(() {
this.sex = value;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("表单"),
),
body: Padding(
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(
hintText: "输入用户信息",
),
onChanged: (v) {
setState(() {
this.username = v;
});
},
),
Row(
children: <Widget>[
Text("男"),
Radio(value: 1, groupValue: this.sex, onChanged: _sexChange),
Text("女"),
Radio(value: 2, groupValue: this.sex, onChanged: _sexChange),
],
),
Column(children: getHobby()),
Container(
width: double.infinity,
height: 40,
child: RaisedButton(
onPressed: () {
setState(() {
this.result = "姓名:${this.username} 性别:${this.sex} 爱好:${this.hobby}";
});
},
child: Text("提交信息"),
),
),
SizedBox(
height: 10,
),
TextField(
maxLines: 5,
// 通过 controller来进行TextField 赋值
controller: TextEditingController.fromValue(
TextEditingValue(
text: result,
// 保持光标在最后
selection: TextSelection.fromPosition(TextPosition(
affinity: TextAffinity.downstream,
offset: result.length
)
),
decoration: InputDecoration(border: OutlineInputBorder()),
)
],
),
),
),
);
}
}