输入框TextField
TextField用于文本输入,基本用法
const TextField(
decoration: InputDecoration(
labelText: '用户名',
hintText: '请输入用户名',
prefixIcon: Icon(Icons.person)
),
)
TextField 属性 | 属性介绍 |
---|---|
controller | 编辑框的控制器,通过它可以设置/获取编辑框的内容、选择编辑内容、监听编辑文本改变事件 |
focusNode | 用于控制TextField是否占有当前键盘的输入焦点。它是我们和键盘交互的一个句柄(handle) |
decoration | 用于控制TextField的外观显示,如提示文本、背景颜色、边框等 |
keyboardType | TextInputType,键盘类型 |
textInputAction | 键盘动作按钮图标(即回车键位图标),它是一个枚举值,有多个可选值 |
textCapitalization | 大小写,默认为 TextCapitalization.none |
style | 字体样式 |
strutStyle | 字体的布局样式 |
textAlign | 输入框内编辑文本在水平方向的对齐方式,默认TextAlign.start |
textAlignVertical | 文字纵轴对齐方式 |
textDirection | TextDirection.ltr 是居左,TextDirection.rtl 是居右,和 textAlign 效果一致 |
readOnly | 只读属性,默认为 false |
toolbarOptions | 长按时弹出的按钮设置,(如赋值,粘贴,全部选中等) |
showCursor | 是否显示光标,默认为 true |
autofocus | 是否自动聚焦,默认为 false |
obscuringCharacter | 加密输入时的替换字符,默认为 '•' |
obscureText | 是否加密,默认为 false |
autocorrect | 是否自动更正,默认为 true |
smartDashesType | SmartDashesType 智能替换破折号,例如连续输入三个'-' 会自动替换成一个'——',当 obseretext == true 时,smartDashesType 默认不可用 |
smartQuotesType | SmartQuotesType 智能替换引号,根据文字情况智能替换为左引号或者右引号,当 obseretext == true 时,SmartQuotesType 默认不可用 |
enableSuggestions | 是否在用户输入时显示输入建议,此标志仅影响Android,默认为 true |
maxLines | 最大行数 |
minLines | 最小行数 |
expands | 是否填充父控件,默认为 false |
maxLength | 最大长度 |
maxLengthEnforcement | 是否强制限制,或者只提供字符计数器和警告,默认为 true |
onChanged | 输入框文字改变回调 |
onEditingComplete | 输入框完成回调 |
onSubmitted | 提交按钮点击回调 |
onAppPrivateCommand | 暂无 |
inputFormatters | 用于指定输入格式;当用户输入内容改变时,会根据指定的格式来校验,注意这里比 onChanged 先执行 |
enabled | 如果为false,则输入框会被禁用,禁用状态不接收输入和事件,同时显示禁用态样式(在其decoration中定义) |
cursorWidth | 光标宽度,默认为 2.0 |
cursorHeight | 光标高度 |
cursorRadius | 光标圆角 |
cursorColor | 光标颜色 |
selectionHeightStyle | 选中高度样式,默认为 ui.BoxHeightStyle.tight |
selectionWidthStyle | 选中宽度样式,默认为 ui.BoxWidthStyle.tight |
keyboardAppearance | 键盘外观,此设置仅适用于iOS设备,iOS的白色以及黑色风格键盘 |
scrollPadding | 滚动后距离边缘的距离,默认为 EdgeInsets.all(20.0) |
dragStartBehavior | 启动阻力,默认为 DragStartBehavior.start |
enableInteractiveSelection | 默认为True,如果为false,则大多数辅助功能支持选择文本、复制和粘贴,移动插入符号将被禁用 |
selectionControls | 暂无 |
onTap | 点击事件 |
mouseCursor | 鼠标悬停,Web可以了解 |
buildCounter | InputDecorator.counter 自定义小工具 |
scrollController | 滚动控制器 |
scrollPhysics | 滚动物理效果 |
autofillHints | 自动填充 |
clipBehavior | 暂无 |
restorationId | 暂无 |
scribbleEnabled | 暂无 |
enableIMEPersonalizedLearning | 暂无 |
keyboardType
的枚举值:
keyboardType 的枚举值 | 介绍 |
---|---|
text | 文本输入键盘 |
multiline | 多行文本,需和maxLines配合使用(设为null或大于1) |
number | 数字;会弹出数字键盘 |
phone | 优化后的电话号码输入键盘;会弹出数字键盘并显示“* #” |
datetime | 优化后的日期输入键盘;Android上会显示“: -” |
emailAddress | 优化后的电子邮件地址;会显示“@ .” |
url | 优化后的url输入键盘; 会显示“/ .” |
controller 的使用
controller
可以监听输入框变化,还可以设置默认值、选择文本。
(1)监听输入框变化 首先创建一个controller:
final TextEditingController _controller = TextEditingController();
然后设置输入框controller:
TextField(
controller: _controller,
decoration: const InputDecoration(
labelText: '用户名',
hintText: '请输入用户名',
prefixIcon: Icon(Icons.person)
),
),
ElevatedButton(
onPressed: (){
//通过controller取值
print(_controller.text);
},
child: const Text('完成')
),
(2)设置默认值、选择文本 创建一个新的controller:
final TextEditingController _selectionController = TextEditingController();
//设置默认值
_selectionController.text = "设置默认值";
//选择文本
_selectionController.selection = TextSelection(
baseOffset: 2,
extentOffset: _selectionController.text.length
);
使用:
TextField(
controller: _selectionController,
),
onChange的使用
//设置onChange回调
TextField(
controller: _controller,
decoration: const InputDecoration(
labelText: '用户名',
hintText: '请输入用户名',
prefixIcon: Icon(Icons.person)
),
onChanged: (v){
print("onChanged':$v");
},
),
focusNode 使用
创建FocusNode对象实例:
final FocusNode _focusNode = FocusNode();
监听焦点状态改变事件:
//输入框焦点事件的捕捉与监听
@override
void initState() {
super.initState();
// Add code after super
//添加listen监听
//对应的TextField失去或者获取焦点都会回调此监听
_focusNode.addListener(() {
bool hasFocus = _focusNode.hasFocus;
bool hasListeners = _focusNode.hasListeners;
//获得焦点时focusNode.hasFocus值为true,失去焦点时为false
if(hasFocus){
//获取焦点
print('获取焦点 $hasFocus',);
}else{
//失去焦点
print('失去焦点 $hasFocus',);
}
});
}
运用:
TextField(
focusNode: _focusNode,//焦点名称
decoration: const InputDecoration(
labelText: '焦点',
),
),
decoration 自定义样式
我们可以通过decoration
属性来定义输入框样式,先看一下decoration
InputDecoration
的构造:
const InputDecoration({
this.icon,
this.iconColor,
this.label,
this.labelText,
this.labelStyle,
...
})
很多属性,就不一一举例了,
单选开关和复选框
单选开关Switch
和复选框Checkbox
,虽然它们都是继承自StatefulWidget
,但它们本身不会保存当前选中状态,选中状态都是由父组件来管理的。当Switch
或Checkbox
被点击时,会触发它们的onChanged
回调,我们可以在此回调中处理选中状态改变逻辑。
单选开关Switch
Switch
为material
风格的开关组件,基本用法如下: 1、定义变量来维护开关的状态:
bool _switchSelected = false; //维护单选开关状态
Switch(
value: _switchSelected,
onChanged: (value){
setState(() {
_switchSelected = value;
});
}
)
效果:
我们来看一下基本属性:
const Switch({
super.key,
required this.value,
required this.onChanged,//改变时触发
this.activeColor,//激活时圆圈的颜色
this.activeTrackColor,//激活时滑槽的颜色
this.inactiveThumbColor,//非激活时圆圈的颜色
this.inactiveTrackColor,//非激活时滑槽的颜色
this.activeThumbImage,//圆圈图片设置,激活时效果
this.onActiveThumbImageError,//打开状态下滑块图片加载失败回调
this.inactiveThumbImage,//圆圈图片非激活效果
this.onInactiveThumbImageError,关闭状态下滑块图片加载失败回调
this.thumbColor,//可以通过不同状态设置滑块颜色
this.trackColor,//可以通过不同状态设置轨道颜色
this.materialTapTargetSize,//内边距,默认最小点击区域为 48 * 48,MaterialTapTargetSize.shrinkWrap 为组件实际大小
this.dragStartBehavior = DragStartBehavior.start,//启动阻力
this.mouseCursor,//鼠标的样式
this.focusColor,//聚焦颜色
this.hoverColor,//鼠标悬停时,外层的大圈颜色,一般用在web
this.overlayColor,//设置按压滑动覆盖上面的颜色
this.splashRadius,//大圈的半径,如果不想要外圈的悬浮效果,可以将半径设为 0
this.focusNode,//焦点控制
this.autofocus = false,//是否自动聚焦
})
激活和非激活的圆圈和滑槽的颜色设置
Switch(
value: _switchSelected,
onChanged: (value){
setState(() {
_switchSelected = value;
});
},
activeColor: Colors.green,//激活时圆点颜色
activeTrackColor: Colors.pink,//激活时滑槽颜色
inactiveThumbColor: Colors.black,//非激活时圆点颜色
inactiveTrackColor: Colors.yellow,//非激活时滑槽颜色
)
效果:
鼠标形状mouseCursor
,用于web
//mouseCursor: SystemMouseCursors.text,
mouseCursor: SystemMouseCursors.grabbing,
圆圈图片设置:
activeThumbImage: const AssetImage('images/avatar.jpg'),//激活时的圆圈图片
inactiveThumbImage: const AssetImage('images/inactive.jpg'),//未激活时的圆圈图片
SwitchListTile
带标题开关
SwitchListTile(
value: _switchSelected,
onChanged: (value){
setState(() {
_switchSelected = value;
});
},
title: const Text('今天是否开心'),
)
CupertinoSwitch
ios风格开关
CupertinoSwitch(
value: _switchSelected,
onChanged: (value){
setState(() {
_switchSelected = value;
});
},
)
复选框Checkbox
1、定义变量来维护开关的状态 :
//Checkbox定义变量
bool? _checkboxSelected = true;
基础用法:
Checkbox(
value: _checkboxSelected,
activeColor: Colors.pink,
onChanged: (value){
setState(() {
_checkboxSelected = value;
});
}
)
我们看一下Checkbox的属性:
const Checkbox({
super.key,
required this.value,
this.tristate = false, //设置复选框是否三态,取值包括true、false和 null
required this.onChanged,////改变时触发
this.mouseCursor,//鼠标样式
this.activeColor,//选中时填充颜色
this.fillColor,//设置单选框不同状态的的颜色
this.checkColor,//选中时中间✔️颜色
this.focusColor,//聚焦颜色
this.hoverColor,//悬停颜色
this.overlayColor,//按压覆盖颜色
this.splashRadius,//光圈大小
this.materialTapTargetSize,//内边距,默认最小点击区域为 48 * 48,MaterialTapTargetSize.shrinkWrap 为组件实际大小
this.visualDensity,//布局紧凑设置
this.shape,//形状
this.side,//自定义选项框边框样式
})
例子:
//属性列子
Checkbox(
value: _checkboxSelected,
activeColor: Colors.pink,
// fillColor: MaterialStateProperty.resolveWith((states) => null),
// fillColor: MaterialStateProperty.all(Colors.cyan),//填充颜色
checkColor: Colors.white,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
// shape: const CircleBorder(),//圆形
//设置成圆角
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(6))
),
//设置未选择边框颜色
side: const BorderSide(color: Colors.black,width: 2,style: BorderStyle.solid),
visualDensity: const VisualDensity(
horizontal: VisualDensity.minimumDensity,
vertical: VisualDensity.minimumDensity
),
onChanged: (value){
setState(() {
_checkboxSelected = value;
});
}
),
//多选列子
class FormPage extends StatefulWidget {
const FormPage({Key? key}) : super(key: key);
@override
State<FormPage> createState() => _FormPageState();
}
class _FormPageState extends State<FormPage> {
List flag = [false,false,false];
List select = ['白玫瑰','红玫瑰','粉玫瑰'];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('表单之多选'),),
body: Container(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Row(
children: [
const Text('选择你喜欢的花'),
Text(select[0]),
Checkbox(
value: flag[0],
onChanged: (v){
setState(() {
flag[0] = v;
});
}
),
Text(select[1]),
Checkbox(
value: flag[1],
onChanged: (v){
setState(() {
flag[1] = v;
});
}
),
Text(select[2]),
Checkbox(
value: flag[2],
onChanged: (v){
setState(() {
flag[2] = v;
});
}
),
],
),
ElevatedButton(
onPressed: (){
String likes = '你选择的花是:';
for(int i = 0;i<flag.length;i++){
if(flag[i]){
likes = '${likes + select[i]} ';
}
}
print(likes);
},
child: const Text('你选择的花是')
)
],
),
),
);
}
}
CheckboxListTile 实现全选和取消
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class FormPage extends StatefulWidget {
const FormPage({Key? key}) : super(key: key);
@override
State<FormPage> createState() => _FormPageState();
}
class _FormPageState extends State<FormPage> {
List flag = [false,false,false];
List select = ['白玫瑰','红玫瑰','粉玫瑰'];
bool isChecked = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('表单'),),
body: Container(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
CheckboxListTile(
title: const Text('全选'),
secondary: const Icon(Icons.flag),///*设置显示的小组件,与□所在位置相反*/
//调整复选框和图标的位置
controlAffinity: ListTileControlAffinity.leading,
value: isChecked,
onChanged: (bool? value){
setState(() {
isChecked = value!;
for(int i = 0 ; i < flag.length; i++){
flag[i] = isChecked;
}
});
}
),
CheckboxListTile(
title: Text(select[0]),
secondary: const Icon(Icons.ac_unit_sharp),
controlAffinity: ListTileControlAffinity.leading,
value: flag[0],
onChanged: (value){
setState(() {
flag[0] = value;
});
}
),
CheckboxListTile(
title: Text(select[1]),
secondary: const Icon(Icons.ac_unit_sharp),
controlAffinity: ListTileControlAffinity.leading,
value: flag[1],
onChanged: (value){
setState(() {
flag[1] = value;
});
}
),
CheckboxListTile(
title: Text(select[2]),
secondary: const Icon(Icons.ac_unit_sharp),
controlAffinity: ListTileControlAffinity.leading,
value: flag[2],
onChanged: (value){
setState(() {
flag[2] = value;
});
}
),
ElevatedButton(
onPressed: (){
String likes = '你选择的花是:';
for(int i = 0;i<flag.length;i++){
if(flag[i]){
likes = '${likes + select[i]} ';
}
}
print(likes);
},
child: const Text('确定')
),
],
),
),
);
}
}
单选 Radio
Radio 属性介绍:
const Radio({
super.key,
required this.value,//@required 是否选中
required this.groupValue,//@required 当前选中的值
required this.onChanged,//@required 点击事件
this.mouseCursor,//鼠标光标
this.toggleable = false,//点击已选中按钮是否调用onChanged回调
this.activeColor,//选中时填充颜色
//其他的同Checkbox
this.fillColor,
this.focusColor,
this.hoverColor,
this.overlayColor,
this.splashRadius,
this.materialTapTargetSize,
this.visualDensity,
this.focusNode,
this.autofocus = false,
})
Radio基础用法:三个必填属性 定义一个性别变量:
int sex = 1;
child: Row(
children: [
const Text('女'),
Radio(
value: 1,
groupValue: sex,
onChanged: (value){
print(value);
setState(() {
sex = value!;
});
}
),
const Text('男'),
Radio(
value: 2,
groupValue: sex,
onChanged: (value){
print(value);
setState(() {
sex = value!;
});
}
)
],
),
表单Form
Form
Form
组件是一个容器类控件,可以包含多个FormField
表单控件,这样的好处是统一管理。
在使用Form
的时候需要设置其key
,通过key
获取当前的FormState
,然后可以调用FormState
的save
、validate
、reset
等方法。Form
继承自StatefulWidget
对象,它对应的状态类为FormState
。我们先看看Form
类的定义:
const Form({
super.key,
required this.child,
this.onWillPop,
this.onChanged,
AutovalidateMode? autovalidateMode,
})
key
组件在整个Widget
树中的key
值。onWillPop
:决定Form
所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个Future
对象,如果Future
的最终结果是false,则当前路由不会返回;如果为true,则会返回到上一个路由。此属性通常用于拦截返回按钮。onChanged
:Form
的任意一个子FormField
内容发生变化时会触发此回调。autovalidateMode
:自动校验。
TextFormField
Flutter 提供了一个TextFormField
组件,它继承自FormField
类,也是TextField
的一个包装类,所以除了FormField
定义的属性之外,它还包括TextField
的属性:
TextFormField({
ValueChanged<String>? onChanged,
GestureTapCallback? onTap,
VoidCallback? onEditingComplete,
ValueChanged<String>? onFieldSubmitted,
super.onSaved,//当 Form 表单调用保存方法 Save 时回调的函数
super.validator,//Form 表单验证器 ,验证回调
List<TextInputFormatter>? inputFormatters,
...
})
TextFormField的基本用法:
TextFormField(
onSaved: (value){
print(value);
},
autovalidateMode: AutovalidateMode.always,
validator: (value){
return value!.trim().isNotEmpty ? null : "用户名不能为空";
},
)
onSaved
是一个可选参数,当Form
调用FormState.save
时才会回调此方法。
validator
验证函数,输入的值不匹配的时候返回的字符串显示在TextField
的errorText
属性位置,返回null
,表示没有错误。
完整例子:
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final GlobalKey _formKey = GlobalKey<FormState>();
//通过controller获取input数据
final TextEditingController _unameController = TextEditingController();
final TextEditingController _pwdController = TextEditingController();
Widget LoginFormWidget(){
return Form(
key: _formKey,//设置globalKey,用于后面获取FormState
autovalidateMode: AutovalidateMode.onUserInteraction,//自动校验
child: Column(
children: [
TextFormField(
controller: _unameController,
autofocus: true,//自动获取焦点
decoration: InputDecoration(
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: (){
_unameController.text = '';
},
),
labelText: "用户名",
hintText: "填写用户名或者邮箱",
icon: const Icon(Icons.person),
),
//校验用户名
validator: (v){
return v!.trim().isNotEmpty ? null :'用户名不能为空';
},
),
TextFormField(
controller: _pwdController,
obscureText: true,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: (){
_pwdController.text = '';
},
),
labelText: "密码",
hintText: "填写密码",
icon: const Icon(Icons.lock),
),
//校验用户名
validator: (v){
return v!.trim().length >5 ? null :'密码不能少于6位';
},
),
Padding(
padding: const EdgeInsets.only(top: 30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed:(){
// 通过_formKey.currentState 获取FormState后,
// 调用validate()方法校验用户名密码是否合法,校验
// 通过后再提交数据。
if((_formKey.currentState as FormState).validate()){
print(_unameController.text);
print(_pwdController.text);
}
} ,
child: const Text('登录')
),
const SizedBox(width: 20,),
ElevatedButton(
onPressed:(){
// 通过_formKey.currentState 获取FormState后,
// 调用validate()方法校验用户名密码是否合法,校验
// 通过后再提交数据。
if((_formKey.currentState as FormState).validate()){
print(_unameController.text);
print(_pwdController.text);
}
} ,
child: const Text('注册')
)
],
),
)
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('表单实例'),),
body: Container(
padding: const EdgeInsets.all(20),
child: LoginFormWidget(),
),
);
}
}
当 Form 表单调用保存方法:不需要controller获取
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final GlobalKey _formKey = GlobalKey<FormState>();
//通过controller获取input数据
final TextEditingController _unameController = TextEditingController();
final TextEditingController _pwdController = TextEditingController();
String? userName; //用户名
String? password; //密码
Widget LoginFormWidget(){
return Form(
key: _formKey,//设置globalKey,用于后面获取FormState
autovalidateMode: AutovalidateMode.onUserInteraction,//自动校验
child: Column(
children: [
TextFormField(
// controller: _unameController,
autofocus: true,//自动获取焦点
decoration: InputDecoration(
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: (){},
),
labelText: "用户名",
hintText: "填写用户名或者邮箱",
icon: const Icon(Icons.person),
),
//校验用户名
validator: (v){
return v!.trim().isNotEmpty ? null :'用户名不能为空';
},
//当 Form 表单调用保存方法 Save时回调的函数。
onSaved: (value){
userName = value;
},
// 当用户确定已经完成编辑时触发
onFieldSubmitted: (value){
},
),
TextFormField(
// controller: _pwdController,
obscureText: true,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: (){},
),
labelText: "密码",
hintText: "填写密码",
icon: const Icon(Icons.lock),
),
//校验用户名
validator: (v){
return v!.trim().length >5 ? null :'密码不能少于6位';
},
//当 Form 表单调用保存方法 Save时回调的函数。
onSaved: (value){
password = value;
},
// 当用户确定已经完成编辑时触发
onFieldSubmitted: (value){},
),
Padding(
padding: const EdgeInsets.only(top: 30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed:(){
// 通过_formKey.currentState 获取FormState后,
// 调用validate()方法校验用户名密码是否合法,校验
// 通过后再提交数据。
// if((_formKey.currentState as FormState).validate()){
// print(_unameController.text);
// print(_pwdController.text);
//
// }
} ,
child: const Text('登录')
),
const SizedBox(width: 20,),
ElevatedButton(
onPressed:(){
// 通过_formKey.currentState 获取FormState后,
var loginForm = _formKey.currentState as FormState;
//调用validate()方法校验用户名密码是否合法,校验
if(loginForm.validate()){
loginForm.save();
print('userName:${userName!},password:${password!}');
}
// 通过后再提交数据。
} ,
child: const Text('调用save方法')
),
const SizedBox(width: 20,),
ElevatedButton(
onPressed:(){
// 通过_formKey.currentState 获取FormState后,
var loginForm = _formKey.currentState as FormState;
loginForm.reset();
} ,
child: const Text('重置')
),
],
),
)
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('表单实例'),),
body: Container(
padding: const EdgeInsets.all(20),
child: LoginFormWidget(),
),
);
}
}