Flutter第九章(TextField ,Form、 Tex
版权声明:本文为作者原创书籍。转载请注明作者和出处,未经授权,严禁私自转载,侵权必究!!!
情感语录: 宽容不是道德,而是认识。唯有深刻地认识事物,才能对人和世界的复杂性有了解和体谅,才有不轻易责难和赞美的思维习惯。
欢迎来到本章节,上一章节我们讲了常用按钮组件
的使用,知识点回顾 戳这里 Flutter基础第八章
本章简要:
1、TextField 文本框组件
2、Form、 TextFormField 组件
3、Checkbox、 CheckboxListTile 多选框组件
4、Radio 、RadioListTile 单选按钮组件
5、Switch 、SwitchListTile 开关组件
一、TextField 文本框组件
用于 Flutter 中用户输入文本的组件,该组件效果类似 Android 原生中的 EditText 控件一样,且更加灵活和多样性。
构造函数如下:
const TextField({
Key key,
this.controller,
this.focusNode,
this.decoration = const InputDecoration(),
TextInputType keyboardType,
this.textInputAction,
this.textCapitalization = TextCapitalization.none,
this.style,
this.strutStyle,
this.textAlign = TextAlign.start,
this.textAlignVertical,
this.textDirection,
this.readOnly = false,
this.showCursor,
this.autofocus = false,
this.obscureText = false,
this.autocorrect = true,
this.maxLines = 1,
this.minLines,
this.expands = false,
this.maxLength,
this.maxLengthEnforced = true,
this.onChanged,
this.onEditingComplete,
this.onSubmitted,
this.inputFormatters,
this.enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
this.keyboardAppearance,
this.scrollPadding = const EdgeInsets.all(20.0),
this.dragStartBehavior = DragStartBehavior.start,
this.enableInteractiveSelection,
this.onTap,
this.buildCounter,
this.scrollController,
this.scrollPhysics,
})
TextField 常见属性
属性 描述
onChanged 文本框内容改变的时候触发的事件
onSubmitted 内容提交(按回车)的回调
decoration 输入前的提示文本等控制,InputDecoration 非常多属性可以配置
border 配置文本框边框 OutlineInputBorder 配合使用
labelText 浮动提示文本的名称
labelStyle 配置 lable 的样式
obscureText 把文本框框改为密码框
controller TextEditingController()可以配置默认值显示信息
textAlign 配置内容在水平方向如何显示
focusNode 绑定焦点控制
textCapitalization 文本框的输入显示格式:
sentences 每个句子的第一个字母被转换成大写。
characters 大写句子中的所有字符
words 对每个单词首字母大写
maxLines 输入框最大的显示行数
maxLengthEnforced 否允许输入的字符长度超过限定的字符长度
readOnly 是否只读
showCursor 是否显示光标
cursorColor 控制光标颜色
cursorRadius 控制光标圆角
cursorWidth 控制光标宽度
autofocus 是否自动获取焦点
maxLength 最大文本长度.设置此项会让TextField右下角有一个输入数量的统计字符串
style TextStyle 配置文本样式
keyboardType 在弹出键盘的时候修改键盘类型,如 TextInputType.number 数字类型
textInputAction 键盘回车键的样式
inputFormatters 限定输入方式,如:WhitelistingTextInputFormatter.digitsOnly 只允许输入数字
onEditingComplete 键盘上按了done
TextField 常常与 InputDecoration 结合使用,所以 InputDecoration 也特别重要。
InputDecoration 常见属性
属性 描述
icon 文本框外配置前置图标
labelText 配置该项可实现文字和文本框联动特效
labelStyle 配置labelText字体样式
helperText 文本框顶部提示信息
helperStyle 配置 helperText 字体样式
hintText 输入前的提示文字
hintStyle 配置hintText文字样式
errorText 错误提示文字 和 helperText 互斥
errorStyle 错误提示文字的样式
errorMaxLines 提示错误文本的最大行数
contentPadding 设置内距
prefixIcon 文本框内配置前置图标 和 icon属性都非常实用
prefix 文本框内配置前置自定义Widget
prefixText 文本框内 配置前置文本
prefixStyle 配置 prefixText 的样式
suffixIcon 文本框内配置后缀图标
suffix 文本框内配置后缀自定义组件
suffixText 文本框内配置后缀 文本
suffixStyle 配置 suffixText 文字样式
counter 配置右下角计数器,通常情况为null
counterText 配置 counter 文本样式
filled 是否填充文本框
fillColor 填充文本框的颜色 filled 为true 生效
border 配置文本框边框 (重要属性)
下面来演示常见用法:
1、普通文本框
什么样式都不配置,默认带一个下划线,直接通过 TextField 可以显示一个最简单的文本框:
TextField()
效果如下:
TextField1.png添加文本框提示信息,和控制输入文字颜色,border:InputBorder.none
可以去掉下划线。
TextField(
//文字样式设置
style: TextStyle(
color: Colors.red,
fontSize: 14,
),
//设置边框属性
//默认的有底部下划线的
decoration: InputDecoration(
//输入前的提示文字
hintText: "请输入留言",
//去掉下划线
// border: InputBorder.none,
//输入前的提示文字样式
hintStyle: TextStyle(
fontWeight: FontWeight.w300, color: Colors.green),
),
),
效果如下:
TextField2.gif2、边框表单、label 特效
OutlineInputBorder
可以为文本框添加边框。
TextField(
decoration: InputDecoration(
//特效label的信息和样式
labelText: '账户',
labelStyle: TextStyle(
color: Colors.deepPurple,
fontSize: 14,
),
//输入前的提示文字和样式
hintText: '请输入账号',
hintStyle: TextStyle(color: Colors.green,fontSize: 14),
//输入框添加边框
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
),
),
),
),
效果如下:
TextField3.gif3、icon 文本框
InputDecoration 支持传入一个 icon 属性,传入之后,会在表单的前面显示一个 icon
Container(
height: 40,
child: TextField(
//设置为密码模式
obscureText: true,
decoration: InputDecoration(
// 边框的内边距
contentPadding: EdgeInsets.all(10),
filled: true,
hintText: '手机号',
hintStyle : TextStyle(color: Colors.green, fontSize: 14),
icon: Icon(Icons.phone),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
),
)
),
),
),
效果如下:
TextField4.gif
4、简单综合运用下:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_learn/util/ToastUtil.dart';
class FormPagePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
String phone = "";
String pass = "";
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Text("FormPage"),
),
body: Container(
margin: EdgeInsets.only(left: 20),
width: 300,
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
SizedBox(height: 40),
Container(
height: 40,
child: TextField(
controller: TextEditingController(text: "187"),
//是否隐藏密码
obscureText: false,
//绑定焦点控制
focusNode: FocusNode(),
textCapitalization: TextCapitalization.sentences,
//控制光标样式
cursorColor: Colors.blue,
cursorRadius: Radius.circular(1.0),
cursorWidth: 1.0,
//最大长度,设置此项会让TextField右下角有一个输入数量的统计字符串
maxLines: 1,
//输入文本的样式
style: TextStyle(fontSize: 14.0, color: Colors.green),
//内容改变的回调
onChanged: (text) {
print('change $text');
phone = text;
},
decoration: InputDecoration(
labelText: '账户',
labelStyle: TextStyle(
color: Colors.deepPurple,
fontSize: 14,
),
// 边框的内边距
contentPadding: EdgeInsets.all(10),
filled: true,
hintText: '手机号',
hintStyle : TextStyle(color: Colors.grey, fontSize: 14),
icon: Icon(Icons.phone),
border: OutlineInputBorder(
//边框圆角
borderRadius: BorderRadius.circular(5.0),
)
),
),
),
SizedBox(height: 10),
Container(
height: 40,
child: TextField(
controller: TextEditingController(),
//是否隐藏密码
obscureText: true,
//绑定焦点控制
focusNode: FocusNode(),
//控制光标样式
cursorColor: Colors.blue,
cursorRadius: Radius.circular(1.0),
cursorWidth: 1.0,
//自动获取焦点
maxLines: 1,
autofocus: false,
//输入文本的样式
style: TextStyle(fontSize: 14.0, color: Colors.green),
//在弹出键盘的时候修改键盘类型
keyboardType: TextInputType.number,
//键盘回车键的样式
textInputAction: TextInputAction.send,
//允许的输入格式 WhitelistingTextInputFormatter.digitsOnly 只允许输入数字
inputFormatters: [
WhitelistingTextInputFormatter.digitsOnly
],
//内容改变的回调
onChanged: (text) {
print('change $text');
pass = text;
},
decoration: InputDecoration(
labelText: '密码',
labelStyle: TextStyle(
color: Colors.deepPurple,
fontSize: 14,
),
// 边框的内边距
contentPadding: EdgeInsets.all(10),
filled: true,
hintText: '密码',
hintStyle : TextStyle(color: Colors.grey, fontSize: 14),
icon: Icon(Icons.lock_outline),
border: OutlineInputBorder(
//边框圆角
borderRadius: BorderRadius.circular(5.0),
)
),
),
),
SizedBox(
height: 30,
),
Container(
height: 40,
child:
RaisedButton(
child:
Text('登录', style: TextStyle(color: Colors.white)),
color: Colors.green,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
onPressed: () {
ToastUtil.show("账号:$phone"+ " 密码:$pass");
},
),
),
],
)
],
),
)));
}
}
效果如下:
TextField5.gif效果还是不错的,更多美美的特效,自己去 DIY 吧 哈哈。
二、Form、 TextFormField 组件
1、Form 组件
Flutter中的Form组件和html中的<form></form>的作用类似,都是起到了一个容器的作用。实际业务中,在正式向服务器提交数据前,都会对各个输入框数据进行合法性校验,但是对每一个TextField都分别进行校验将会是一件很麻烦的事。还有,如果用户想清除一组TextField的内容,除了一个一个清除有没有什么更好的办法呢?为此,Flutter提供了一个Form 组件,它可以对输入框进行分组,然后进行一些统一操作,如输入内容校验、输入框重置以及输入内容保存。
构造函数:
const Form({
Key key,
@required this.child,
this.autovalidate = false,
this.onWillPop,
this.onChanged,
})
Form 常用属性:
属性 描述
autovalidate 是否自动校验输入内容。
onWillPo 此属性通常用于拦截返回按钮。
onChanged Form的任意一个子FormField内容发生变化时会触发此回调。
2、TextFormField 组件
Flutter提供了一个TextFormField 组件,它继承自 FormField
类,也是 TextField 的一个包装类,所以除了 FormField 定义的属性之外,它还包括TextField 的属性。FormState
为 Form 的State 类,可以通过Form.of()
或 GlobalKey
获得。我们可以通过它来对 FormField 进行统管理。我们看看其常用的三个方法:
FormState.validate()
:调用此方法后,会调用Form子孙FormField的validate
回调,如果有一个校验失败,则返回false,所有校验失败项都会返回用户返回的错误提示。
FormState.save()
:调用此方法后,会调用Form子孙FormField的save回调,用于保存表单内容。
FormState.reset()
:调用此方法后,会将子孙FormField的内容清空。
FormField 构造函数
const FormField({
...
FormFieldSetter<T> onSaved, //保存回调
FormFieldValidator<T> validator, //验证回调
T initialValue, //初始值
bool autovalidate = false, //是否自动校验。
})
特别注意的是在 TextFormField 中没有 onChanged ()
回调函数给我们取出输入框中的值,必须使用 controller
方式 添加监听。
简单运用:
我们修改一下上面用户登录的示例,在提交之前校验:1.用户名不能为空,如果为空则提示“用户名不能为空”。2.密码不能小于6位,如果小于6为则提示“密码不能少于6位”。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_learn/util/ToastUtil.dart';
class FormPagePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Text("FormPage"),
),
body: Container(
margin: EdgeInsets.only(left: 20),
width: 300,
child: ListView(
children: <Widget>[
///文本框组件
//TextFieldWidget()
///表单提交校验
FormFieldWidget()
],
),
)));
}
}
//登录验证的表单
class FormFieldWidget extends StatefulWidget {
@override
_FormFieldWidgetState createState() => _FormFieldWidgetState();
}
class _FormFieldWidgetState extends State<FormFieldWidget> {
TextEditingController _unameController = new TextEditingController();
TextEditingController _pwdController = new TextEditingController();
GlobalKey _formKey= new GlobalKey<FormState>();
String userName = "";
String userPass = "";
@override
void initState() {
super.initState();
//添加监听
_unameController.addListener((){
userName =_unameController.text;
});
_pwdController.addListener((){
userPass = _pwdController.text;
});
}
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
child: Form(
key: _formKey, //设置globalKey,用于后面获取FormState
autovalidate: true, //开启自动校验
child: Column(
children: <Widget>[
TextFormField(
autofocus: true,
controller: _unameController,
decoration: InputDecoration(
labelText: "用户名",
hintText: "用户名或邮箱",
icon: Icon(Icons.person)
),
// 校验用户名
validator: (v) {
return v
.trim()
.length > 0 ? null : "用户名不能为空";
}
),
TextFormField(
controller: _pwdController,
decoration: InputDecoration(
labelText: "密码",
hintText: "您的登录密码",
icon: Icon(Icons.lock)
),
obscureText: true,
//校验密码
validator: (v) {
return v
.trim()
.length > 5 ? null : "密码不能少于6位";
}
),
// 登录按钮
Padding(
padding: const EdgeInsets.only(top: 28.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
padding: EdgeInsets.all(15.0),
child: Text("登录"),
color:Colors.blue,
textColor: Colors.white,
onPressed: () {
// 通过_formKey.currentState 获取FormState后,
// 调用validate()方法校验用户名密码是否合法,校验
// 通过后再提交数据。
FormState state = (_formKey.currentState as FormState);
if(state.validate()){
ToastUtil.show("账号:$userName" + " 密码:$userPass");
//验证通过提交数据,并清空表单
//state.reset();
}
},
),
),
],
),
)
],
),
),
);
}
}
效果如下:
表单验证.gif三、Checkbox、 CheckboxListTile 多选框组件
1、Checkbox组件
Checkbox复选框按钮有自带的一个动画效果,但是它并未像其他组件那么完美,没有提示文本信息的配置,因此要往往需要和其他组件组合使用
构造函数:
const Checkbox({
Key key,
@required this.value,
this.tristate = false,
@required this.onChanged,
this.activeColor,
this.checkColor,
this.materialTapTargetSize,
})
Checkbox 常见属性:
属性 描述
value true 或者 false
onChanged 改变的时候触发的事件
activeColor 选中的颜色、背景颜色
checkColor 选中的颜色、Checkbox 里面对号的颜色
简单运用:
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Checkbox(
value: _isSelected,
onChanged: (v) {
setState(() {
this._isSelected = v;
});
},
activeColor: Colors.red,
checkColor: Colors.blue),
SizedBox(width: 50),
Checkbox(
activeColor: Colors.green,
checkColor: Colors.yellow,
value: this._isSelected,
onChanged: (value) {
setState(() {
this._isSelected = value;
});
},
),
Container(
child: Text(this._isSelected ? '选中' : '未选中'),
),
],
)
效果如下:
Checkbox.gif2、CheckboxListTile 组件
CheckboxListTile 提供了类似 ListTile 样式的多选框,使用它可以很轻松实现类似商品购物栏样式。
CheckboxListTile 常见属性:
属性 描述
value true 或者 false
onChanged 改变的时候触发的事件
activeColor 选中的颜色、背景颜色
title 标题
subtitle 二级标题
secondary 配置图标或者图片
selected 选中的时候文字颜色是否跟着改变
简单运用:
CheckboxListTile(
title: Text('标题'),
subtitle: Text('二级标题'),
activeColor: Colors.pink,
selected: this._isSelected,
secondary: Image.asset(
"images/mm.jpg",
fit: BoxFit.cover,
// color: Colors.grey[200],
width: 60,
),
value: this._isSelected,
onChanged: (value) {
setState(() {
this._isSelected = value;
});
},
),
效果如下:
CheckboxListTile.gif四、Radio 、RadioListTile 单选按钮组件
1、Radio 组件:
Radio单独使用和 Checkbox 是一样的效果。Radio 往往都是需要多个 一起使用,因此多个 Radio 往往绑定的是同一个 state。多个Radio一起使用就形成了RadioGroup,而 RadioGroup 怎么去区分众多中的 Radio 是和自己一组的呢?于是 Radio 要实现单选效果就多了一个必传属性groupValue
,只要 groupValue 指向同一个变量,就说明这些 Radio 是同一个 group 中的,就只会有一个被选中。
构造函数:
const Radio({
Key key,
@required this.value,
@required this.groupValue,
@required this.onChanged,
this.activeColor,
this.materialTapTargetSize,
}) : super(key: key);
Radio常用属性:
属性 描述
value 单选的值
onChanged 改变时触发
activeColor 选中的颜色、背景颜色
groupValue 选择组的值
简单运用:
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Radio(
value: 0,
activeColor: Colors.blue,
// 绑定_sex变量的 的 Radio 为同一 Group.
groupValue: this._sex,
onChanged: (value) {
setState(() {
this._sex = value;
});
},
),
Text('男'),
Radio(
value: 1,
activeColor: Colors.blue,
groupValue: this._sex,
onChanged: (value) {
setState(() {
this._sex = value;
});
},
),
Text('女'),
],
),
Row(
children: <Widget>[
Text('性别:${this._sex} : ${this._sex == 0 ? '男' : '女'}'),
],
),
效果如下:
Radio.gif2、RadioListTile 组件:
同 CheckboxListTile 一样,也是基于 ListTile 实现,不过会多一个 groupValue 属性,同理 groupValue 绑定统一的变量的成 RadioGroup 组,实现选择互斥,只能选中一个。
构造函数:
const RadioListTile({
Key key,
@required this.value,
@required this.groupValue,
@required this.onChanged,
this.activeColor,
this.title,
this.subtitle,
this.isThreeLine = false,
this.dense,
this.secondary,
this.selected = false,
this.controlAffinity = ListTileControlAffinity.platform,
})
RadioListTile 常用属性:
属性 描述
value true 或者 false
onChanged 改变的时候触发的事件
activeColor 选中的颜色、背景颜色
title 标题
subtitle 二级标题
secondary 配置图标或者图片
groupValue 选择组的值
selected 是否选中
简单运用:
RadioListTile(
activeColor: Colors.pink,
title: Text('标题'),
subtitle: Text('二级标题'),
secondary: Image.asset(
"images/mm.jpg",
fit: BoxFit.cover,
// color: Colors.grey[200],
width: 60,
),
selected: this._sex == 0,
value: 0,
groupValue: this._sex,
onChanged: (value) {
setState(() {
this._sex = value;
});
},
),
Divider(height: 1),
RadioListTile(
activeColor: Colors.pink,
title: Text('标题'),
subtitle: Text('二级标题'),
secondary: Image.asset(
"images/mm.jpg",
fit: BoxFit.cover,
// color: Colors.grey[200],
width: 60,
),
selected: this._sex == 1,
value: 1,
groupValue: this._sex,
onChanged: (value) {
setState(() {
this._sex = value;
});
},
),
效果如下:
RadioListTile.gif五、Switch 、SwitchListTile 开关组件
1、Switch 组件
Switch 组件比较简单,Switch 是 Android 风格的样式,IOS风格 使用 CupertinoSwitch
组件。
构造函数:
const Switch({
Key key,
@required this.value,
@required this.onChanged,
this.activeColor,
this.activeTrackColor,
this.inactiveThumbColor,
this.inactiveTrackColor,
this.activeThumbImage,
this.inactiveThumbImage,
this.materialTapTargetSize,
this.dragStartBehavior = DragStartBehavior.start,
})
Switch 常用属性:
属性 描述
value 是否选中
onChanged 改变时触发
activeColor 选中的颜色、背景颜色
activeThumbImage 原点还支持图片,激活时的效果
activeTrackColor 激活时横条的颜色
inactiveThumbColor 非激活时原点的颜色
inactiveThumbImage 非激活原点的图片效果
inactiveTrackColor 非激活时横条的颜色
简单运用:
Container(
width: 60,
child: Switch(
//当前状态
value: _switchSelected,
// 激活时原点颜色
activeColor: Colors.blue,
activeTrackColor: Colors.blue.shade50,
inactiveTrackColor: Colors.blue.shade50,
onChanged: (value) {
//重新构建页面
setState(() {
_switchSelected = value;
});
},
),
),
SizedBox(
height: 20,
),
SizedBox(
height: 20,
child: Text("IOS风格"),
),
CupertinoSwitch(
value: _switchSelected,
// 激活时原点颜色
activeColor: Colors.blue,
onChanged: (value) {
//重新构建页面
setState(() {
_switchSelected = value;
});
},
),
效果如下:
Switch&&CupertinoSwitch.gif2、SwitchListTile 组件
SwitchListTile 组件可以快速实现一些像设置界面的开关场景。
构造函数:
const SwitchListTile({
Key key,
@required this.value,
@required this.onChanged,
this.activeColor,
this.activeTrackColor,
this.inactiveThumbColor,
this.inactiveTrackColor,
this.activeThumbImage,
this.inactiveThumbImage,
this.title,
this.subtitle,
this.isThreeLine = false,
this.dense,
this.secondary,
this.selected = false,
})
SwitchListTile 常用属性
属性 描述
value 是否选中的改变值。
onChanged 改变时触发
activeColor 选中的颜色、背景颜色
activeThumbImage 原点还支持图片,激活时的效果。
activeTrackColor 激活时横条的颜色。
inactiveThumbColor 非激活时原点的颜色。
inactiveThumbImage 非激活原点的图片效果。
inactiveTrackColor 非激活时横条的颜色。
title 一级标题
subtitle, 二级标题
isThreeLine 是否三行文本高度显示
selected 是否选中
简单运用:
SwitchListTile(
secondary: Icon(Icons.wifi),
//一级标题
title: Text('wifi开关'),
//二级标题
subtitle: Text("选中可以打开wifi"),
value: _switchSelected,
//添加三行文本显示高度
isThreeLine: true,
onChanged: (bool value) {
setState(() {
_switchSelected = !_switchSelected;
});
},
),
效果如下:
SwitchListTile.gif在 Android 原生中要实现这些炫酷的效果,自带控件是不可能的,基本都要去自定义View,花销时间巨大,成本过高! 而在Flutter 中这一切都显得那么简单易用,你有没有被Flutter 中这些炫酷的效果吸引到呢?
由于篇幅已经相当长了,且涉及到的知识点较多~~~~~~本章节到此结束,又到了说再见的时候了,如果你喜欢请留下你的小红星,你们的支持才是创作的动力,如有错误,请热心的你留言指正, 谢谢大家观看,下章再会 O(∩_∩)O