文本框TextField
属性列表
TextEditingController controller,
FocusNode focusNode,
InputDecoration decoration = const InputDecoration(),
TextInputType keyboardType,
TextInputAction textInputAction,
TextStyle style,
TextAlign textAlign = TextAlign.start,
bool autofocus = false,
bool obscureText = false,
int maxLines = 1,
int maxLength,
bool maxLengthEnforced = true,
ValueChanged onChanged,
VoidCallback onEditingComplete,
ValueChanged onSubmitted,
List inputFormatters,
bool enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
属性讲解
`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文档,下面是当值为TextInputAction.search时,键盘右下角有搜索,前往等设置。
`style`:正在编辑的文本样式。
`textAlign`: 输入框内编辑文本在水平方向的对齐方式。
`autofocus`: 是否自动获取焦点。
`obscureText`:是否隐藏正在编辑的文本,如用于输入密码的场景等,文本内容会用“•”替换。
`maxLines`:输入框的最大行数,默认为1;如果为null,则无行数限制。
`maxLength`和`maxLengthEnforced` :maxLength代表输入框文本的最大长度,设置后输入框右下角会显示输入的文本计数。maxLengthEnforced决定当输入文本长度超过maxLength时是否阻止输入,为true时会阻止输入,为false时不会阻止输入但输入框会变红。
`onChange`:输入框内容改变时的回调函数;注:内容改变事件也可以通过controller来监听。
`onEditingComplete`和`onSubmitted`:这两个回调都是在输入框输入完成时触发,比如按了键盘的完成键(对号图标)或搜索键(图标)。不同的是两个回调签名不同,onSubmitted回调是ValueChanged类型,它接收当前输入内容做为参数,而onEditingComplete不接收参数。
`inputFormatters`:用于指定输入格式;当用户输入内容改变时,会根据指定的格式来校验。
`enable`:如果为false,则输入框会被禁用,禁用状态不接收输入和事件,同时显示禁用态样式(在其decoration中定义)。
`cursorWidth`、`cursorRadius`和`cursorColor`:这三个属性是用于自定义输入框光标宽度、圆角和颜色的。
外观设置
TextField(
controller: controller,
decoration: InputDecoration(
labelText: "密码", ## labelText设置标签文字,这个标签在没有输入的时候是占满输入框的,当输入聚焦以后,就会缩小到输入框左上角:
hintText: "您的登录密码", ##placeholder
prefixIcon: Icon(Icons.lock) ## 前面的icon
fillColor: Colors.blue.shade100, ##填充颜色
filled: true, ## 充满
errorText: 'error' ## 错误提示
helperText: 'help', ##提示文本
suffixText: 'airport', ##后缀
// 边框设置
// border: InputBorder.none //隐藏下划线
contentPadding: EdgeInsets.all(10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
borderSide: BorderSide(color: Colors.red, width: 3.0, style:
BorderStyle.solid)//没什么卵效果
)),
),
maxLength: 30,//最大长度,设置此项会让TextField右下角有一个输入数量的统计字符串
maxLines: 1,//最大行数
autocorrect: true,//是否自动更正
autofocus: true,//是否自动对焦
obscureText: true,//是否是密码
textAlign: TextAlign.center,//文本对齐方式
style: TextStyle(fontSize: 30.0, color: Colors.blue),//输入文本的样式
inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],//允许的输入格式
enabled: true,//不禁用
);
监听字符变化,设置默认字符
要监听就要有监听控制器 TextEditingController()
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class TextFieldPage extends StatelessWidget {
Widget buildTextField(TextEditingController controller) {
return TextField(
controller: controller,
maxLength: 30,//最大长度,设置此项会让TextField右下角有一个输入数量的统计字符串
maxLines: 1,//最大行数
autocorrect: true,//是否自动更正
autofocus: true,//是否自动对焦
obscureText: true,//是否是密码
textAlign: TextAlign.center,//文本对齐方式
style: TextStyle(fontSize: 30.0, color: Colors.blue),//输入文本的样式
inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],//允许的输入格式
onChanged: (text) {//内容改变的回调
print('change $text');
},
onSubmitted: (text) {//内容提交(按回车)的回调
print('submit $text');
},
enabled: true,//是否禁用
);
}
@override
Widget build(BuildContext context) {
final controller = TextEditingController();
controller.text="hello world!"; ## 设置默认值
controller.selection=TextSelection(
baseOffset: 2, ###并从第三个字符开始选中后面的字符
extentOffset: controller.text.length
);
controller.addListener(() { ## 监听
print('input ${controller.text}');
});
return Scaffold(
appBar: AppBar(
title: Text('TextField'),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: buildTextField(controller),
),
);
}
}
键盘相关
FocusNode和FocusScopeNode两个属性控制
class FocusTestRoute extends StatefulWidget {
@override
_FocusTestRouteState createState() => new _FocusTestRouteState();
}
class _FocusTestRouteState extends State {
FocusNode focusNode1 = new FocusNode(); ## 初始化对象
FocusNode focusNode2 = new FocusNode(); ## 初始化对象
FocusScopeNode focusScopeNode;
// 监听焦点变化
focusNode.addListener((){
print(focusNode.hasFocus);
});
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
autofocus: true,
focusNode: focusNode1, //关联focusNode1
decoration: InputDecoration(
labelText: "input1"
),
),
TextField(
focusNode: focusNode2, //关联focusNode2
decoration: InputDecoration(
labelText: "input2"
),
),
Builder(builder: (ctx) {
return Column(
children: [
RaisedButton(
child: Text("移动焦点"),
onPressed: () {
//将焦点从第一个TextField移到第二个TextField
// 这是一种写法 FocusScope.of(context).requestFocus(focusNode2);
// 这是第二种写法
if(null == focusScopeNode){
focusScopeNode = FocusScope.of(context); ##初始化焦点第一个,从全文按顺序查找
}
focusScopeNode.requestFocus(focusNode2); ##移动焦点到第二个
},
),
RaisedButton(
child: Text("隐藏键盘"),
onPressed: () {
// 当所有编辑框都失去焦点时键盘就会收起
focusNode1.unfocus(); ### 取消焦点操作
focusNode2.unfocus(); ### 取消焦点操作
},
),
],
);
},
),
],
),
);
}
}
From
对一组文本进行相同的校验
Form 的子空间必须是FormField(和textfild基本一样)
Form属性
Form({
@required Widget child,
bool autovalidate = false, ##是否自动校验输入内容
WillPopCallback onWillPop, ##拦截返回按钮
VoidCallback onChanged, ##Form的任意一个子FormField内容发生变化时会触发此回调
})
FormField
const FormField({
...
FormFieldSetter onSaved, //保存回调
FormFieldValidator validator, //验证回调
T initialValue, //初始值
bool autovalidate = false, //是否自动校验。
})
FormState
FormState为Form的State类,可以通过Form.of()或GlobalKey获得。我们可以通过它来对Form的子孙FormField进行统一操作。我们看看其常用的三个方法:
FormState.validate():调用此方法后,会调用Form子孙FormField的validate回调,如果有一个校验失败,则返回false,所有校验失败项都会返回用户返回的错误提示。
FormState.save():调用此方法后,会调用Form子孙FormField的save回调,用于保存表单内容
FormState.reset():调用此方法后,会将子孙FormField的内容清空。
例子
class FormTestRoute extends StatefulWidget {
@override
_FormTestRouteState createState() => new _FormTestRouteState();
}
class _FormTestRouteState extends State {
TextEditingController _unameController = new TextEditingController();
TextEditingController _pwdController = new TextEditingController();
GlobalKey _formKey= new GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:Text("Form Test"),
),
body: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
child: Form(
key: _formKey, //设置globalKey,用于后面获取FormState
autovalidate: true, //开启自动校验
child: Column(
children: [
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: [
Expanded(
child: RaisedButton(
padding: EdgeInsets.all(15.0),
child: Text("登录"),
color: Theme
.of(context)
.primaryColor,
textColor: Colors.white,
onPressed: () {
//在这里不能通过此方式获取FormState,context不对
//print(Form.of(context));
// 通过_formKey.currentState 获取FormState后,
// 调用validate()方法校验用户名密码是否合法,校验
// 通过后再提交数据。
if((_formKey.currentState as FormState).validate()){
//验证通过提交数据
}
},
),
),
],
),
)
],
),
),
),
);
}
}