Flutter TextField 交互实例 —— 新手礼包
大家好,我是 17。
新手礼包一共 3 篇文章,每篇都是描述尽量详细,实例讲解,包会!
- Flutter Row 实例 —— 新手礼包
- Flutter TextField UI 实例 —— 新手礼包
- Flutter TextField 交互实例 —— 新手礼包
本篇包含所有常见 TextField 交互示例。
设置初始值
在上一篇 Flutter TextField UI 实例 中第一个示例中已经给出了全部代码,并准备好了 controller。
我们梳理一下设置初始值需要的步骤,需要两步完成设置初始值。
- 初始化 controller
var controller = TextEditingController(text: "IAM17");
- 把 controller 赋值给 TextField
TextField(controller: controller,);
完成这两步后,在 TextField 中自就会有文本 “IAM17”。
获取和修改 TextField 内容
有两个办法可以拿到内容。
- 监听 onChange
TextField(controller: controller,onChanged: (value) {print(value);},);
通过 controller 修改文本不会触发 onChange
- 用 controller 拿到 value。
Column(mainAxisSize: MainAxisSize.min, children: [ElevatedButton(onPressed: () {print(controller.text);},child: Text('获取内容')),TextField(controller: controller,)
]);
或者当文本发生改变时获取文本
@overridevoid initState() {controller.addListener(() {print(controller.text);});super.initState();}
- 用 controller 可以随时修改 TextField 内容
比如可以随时清空 TextField。
Column(mainAxisSize: MainAxisSize.min, children: [ElevatedButton(onPressed: () {controller.text='';},child: Text('清空')),TextField(controller: controller,)]);
清空内容还可以用 controller.clear()
。
注意:controller 必须在 disapose 方法中销毁。
@overridevoid dispose() {controller.dispose();super.dispose();}
控制 TextField Focus
自动获得焦点
TextField(autofocus: true,);
手动让一个 TextField 获得或失去焦点
手动获得焦点分四步
- 创建 focusNode。
- 把 focusNode 赋值给 TextField。
- 手动触发 focusNode 的 previousFocus、unfocus 方法获得和失去焦点。
- 在 dispose 中销毁 focusNode。
class MyWidget extends StatefulWidget {const MyWidget({super.key});@overrideState<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {FocusNode focusNode = FocusNode(); //第一步@overridevoid dispose() {focusNode.dispose(); //第四步super.dispose();}@overrideWidget build(BuildContext context) {return Column(mainAxisSize: MainAxisSize.min,children: [TextField(focusNode: focusNode, // 第二步)ElevatedButton(onPressed: () { // 第三步focusNode.hasFocus? focusNode.unfocus(): focusNode.requestFocus();},child: Text('变换焦点')), ],);}
}
如果是在手机上执行代码,会看到 TextField 获取焦点的时候会弹出软键盘,失去焦点的时候,软键盘收起。
监听获取焦点和失去焦点
因为 focusNode 混入了 ChangeNotifier,所以可以直接监听他的状态变化。
class _MyWidgetState extends State<MyWidget> {var focusNode = FocusNode();@overridevoid initState() {focusNode.addListener(() {print(focusNode.hasFocus);});super.initState();}@overridevoid dispose() {focusNode.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return TextField(focusNode: focusNode,);}
}
控制焦点在不同 TextField 间切换
两个 TextField,第一个自动获得焦点,点击按钮,焦点从第一个 TextField 切换到第二个,再次点击,焦点从第二个 TextField 回到第一个。
class MyWidget extends StatefulWidget {const MyWidget({super.key});@overrideState<MyWidget> createState() => _MyWidgetState();
}class _MyWidgetState extends State<MyWidget> {var focusNode1 = FocusNode();var focusNode2 = FocusNode();@overrideWidget build(BuildContext context) {return Column(mainAxisSize: MainAxisSize.min,children: [TextField(autofocus: true,focusNode: focusNode1,),const SizedBox(height: 10,),TextField(focusNode: focusNode2,autofocus: true,),const SizedBox(height: 10,),ElevatedButton(onPressed: () {if (focusNode1.hasFocus) {focusNode1.nextFocus();} else {focusNode2.previousFocus();}},child:const Text('切换焦点')),],);}
}
这是两个 TextField 连续的情况,如果不连续呢?可以用 FocusScope!
把 onPressed 代码修改为:
ElevatedButton(onPressed: () {if (focusNode1.hasFocus) {FocusScope.of(context).requestFocus(focusNode2);} else {FocusScope.of(context).requestFocus(focusNode1);}},child: const Text('切换焦点'))
控制字母大小写的 textCapitalization
textCapitalization 用来控制字母的大小写。不常用,了解一下即可。
- 每个单词的第一字母大写
TextCapitalization.words
- 第个句子的第一个字母大写
TextCapitalization.sentences
- 每个字母都大写
TextCapitalization.characters
- 每个字母默认小写
TextCapitalization.none
可能会用到的是 TextCapitalization.characters
,把输入的所有小写字母转换为大写。
TextField(textCapitalization: TextCapitalization.characters,),
keyboardType 控制键盘
显示数字键盘TextInputType.number
TextField(keyboardType: TextInputType.number);
不显示键盘 TextInputType.none
当 TextField 获得焦点后,不弹出键盘。
更多类型请见 TextInputType
以密码方式显示
TextField(obscureText:true
);
一般会加一个象征密码的图标
TextField(obscureText:true,decoration: InputDecoration(prefixIcon: Icon(Icons.lock)),);
键盘的操作按钮类型 TextInputAction
默认情况下为 TextInputAction.done
。TextField 设置为多行时为 TextInputAction.newline
。
ios 不能设置 TextInputAction.done,默认为 null。
看文字描述可能不大好理解,还是用TextInputAction.search
举个例子吧。
可能你的手机上显示的是一个搜索图标,
TextField(onSubmitted: (value) {print(value);},textInputAction: TextInputAction.search,
)
键盘上原来的 action button 的文本被替换为 搜索。点搜索会触发提交,onSubmitted 被调用。
虽然TextInputAction.search
表明点击按钮后应该进行搜索,但是否执行搜索由开发者决定。
我们再试一下 TextInputAction.newline 的行为。
TextField(maxLines: 3,
);
maxLines: 3
可以让 TextField 输入多行,点击 action button 会让 TextField 光标换行。
Flutter 中存在 TextInputAction.newline ,但 Android 或 iOS 中不存在。引入这个术语的原因是开发者可以实现插入新行的通用结果,而无需了解 Android 上的各种 IME 操作和 iOS 上的返回键。
默认的 tooltip 提示语为英文?
如果你新建了一个项目,还没有做国际化,直接用 TextField,tooltip 的提示语是英文。可以这样操作一下:长按 TextField 输入框,这时会弹出一个提示框上面写着 Paste。
这是因为没有设置国际化的原因。
想要使用 flutter_localizations 的话,我们需要在 pubspec.yaml
文件中添加它作为依赖:
dependencies:flutter:sdk: flutterflutter_localizations:sdk: flutter
MaterialApp(supportedLocales: [Locale("en"),Locale("zh")],localizationsDelegates: [GlobalMaterialLocalizations.delegate,GlobalWidgetsLocalizations.delegate,GlobalCupertinoLocalizations.delegate],)
maxLength 与 counterText
TextField(maxLength: 6,),
counterText 就是显示在右下角的文本。当指定 maxLength 时,会自动显示 counterText,当达到最大字数时,无法再输入。可以用maxLengthEnforcement: MaxLengthEnforcement.none
改变这种限制,字符数超过 maxLength 后也能继续输入。不过,超过限制后,默认会显示红色的 errrorBorder 和 红色的 errorText
TextField(maxLength: 3,maxLengthEnforcement: MaxLengthEnforcement.none);
maxLengthEnforcement 一共有三个可选值。
- 没有限制
MaxLengthEnforcement.none
- 严格限制,超出后无法再输入
MaxLengthEnforcement.enforced
- 即使在达到最大长度限制后,如果当前值正在撰写,用户仍然可以输入文本。合成结束后,该值将被截断
MaxLengthEnforcement.truncateAfterCompositionEnds
第三条我解释一下。对于中文来说,我们用拼音打字的时候,首先会输入一些字母,这些字母会出现在输入框中,出现想要的汉字后再确认(也可能会自动上屏),让汉字出现在输入框中。字符数超出 maxLength 的时候,第三条允许这些字母出现在输入框中,第二条不允许。
我们用 chrome 浏览查看下效果。打开 chrome 浏览器,输入法调到拼音。要想在地址栏中输入天,需要输入字母 tian,当你输入 t 的时候,t 就已经出现在地址栏中了。随着字母 i,a,n 的输入,候选汉字不断变换,当出现你想到的汉字的时候,按空格(或是其它的上屏按键),地址栏中的字母消失,被 天 替代。如果 maxLength 是 1,MaxLengthEnforcement.enforced
只允许显示 字母 t,MaxLengthEnforcement.truncateAfterCompositionEnds
允许显示全部的 tian,这对于汉字的输入是非常有用的,默认情况下,TextField 的 MaxLengthEnforcement 就是 MaxLengthEnforcement.truncateAfterCompositionEnds
。
虽然是用 chrome 浏览器地址栏举的例子,TextField 也是一样的。可以用 web 方式在 chrome 中查看 TextField 的表现,效果是一样的。
当 maxLength 为 -1 的时候,表示没有最大限制,输入多少个字符都可以。counterText 只显示当前字符数,不显示最大值。-1 用 TextField.noMaxLength 表示。
TextField(maxLength: TextField.noMaxLength ,),
自定义 counterText 样式
默认的 counterText 是很小的,我们想把他变大一些。
两种方法,一个是用 theme,我们这次用局部 theme(相当于 css 中的局部样式表)。先获得父级样式,用 copywith 方法,把新的样式补充进来。当 counterStyle 为 null 的时候,counterText 采用 helperStyle,要想同时影响到 helperText,也可以定义 helperStyle。
var themeData = Theme.of(context);var decorationTheme = themeData.inputDecorationTheme;return Theme(data: themeData.copyWith(inputDecorationTheme:decorationTheme.copyWith(counterStyle: TextStyle(fontSize: 20))),child: TextField(maxLength: 6),
);
另一个方法是直接用 counterStyle
TextField(maxLength: 6,decoration: InputDecoration(counterStyle: TextStyle(fontSize: 20)),);
当 maxLengthEnforcement: MaxLengthEnforcement.none
,输入字数超过最大字符数后,border ,counterText 都显示为红色。这个时候 counterText 的样式是 errorStyle 控制的。我们可以修改为其它样式。errorStyle 还会影响 errorText 的样式。
我们定义错误时 counterText 显示为绿色。
InputDecoration(errorStyle: TextStyle(color: Colors.green),);
自定义 counterText
maxLength 设为 3,我们要实现下面的效果:字符数没有超过 3 时 currentCount 样式为黑色,超过 3 时显示为红色。
TextField(style: const TextStyle(color: Color(0xFFC45F84), fontSize: 24),maxLength: 3,maxLengthEnforcement: MaxLengthEnforcement.none,decoration: const InputDecoration(counterStyle: TextStyle(fontSize: 20)),buildCounter: (context,{required currentLength, required bool isFocused, maxLength}) {return Text.rich(TextSpan(children: [TextSpan(text: '$currentLength',style: TextStyle(color:currentLength>maxLength!? Colors.red:Colors.black)),const TextSpan(text: ' / '),TextSpan(text: '$maxLength')]));},);
用 buildCounter 生成 counterText ,当字符数超过最大限制数后,TextField 不再显示错误状态,border 显示为 focusBorder 样式。
用 Text.rich ,包含多个 TextSpan,以便加不同的样式。上面的代码实现了所有的功能,但是有一个隐患,当 maxLength 为TextField.noMaxLength
的时候,maxLength 为 -1
,不应该直接显示,应该处理一下:当 maxLength 为 -1 的时候,直接不显示了。
if (maxLength >= 0) const TextSpan(text: ' / '),
if (maxLength >= 0) TextSpan(text: '$maxLength')
decoration 的 counterText 与 counter 属性
用 buildCounter 自定义 counterText 完全没有问题,为什么还要弄出这两个属性来呢?我们看下他们的作用。
- 当 counterText 不为 null ,buildCounter 被忽略。
- 当 counter 不为 null,counterText 被忽略。
由此可见,如果不想显示 countText,设置 counterText: ''
和定义 buildCounter 的效果一样,字符超出最大限制后,TextField 也不再显示错误状态,border 显示为 focusBorder 样式。
TextField(decoration: InputDecoration(counterText: ''),);
如果要用 counter ,counterText 显示内容的话,不适合动态显示字符数,虽然能实现,但不如用 buildCounter 方便。如果非要显示内容的话,可以放一些提示语什么的,类似于 helperText。
设置 TextField 的显示行数,maxLines 与 maxLines
默认显示一行,超出后横向滚动。不能换行。
调整默认 TextField 默认显示行数的参数有两个 minLines,maxLines。 他们规定了初始显示的行数,但并不限制可以输入的最大行数。
设置 maxLines: 3
,TextField 默认 显示 3 行,可以从第一行输入,连续输入三行,过超三行,还可以输入,但会坚向滚动。
设置 maxLines: null
,TextField 默认 显示 1 行,可以从第一行输入,连续输入第二行,第三行,无限行,超过约束的最大高度后,坚向滚动。
设置 minLines:2, maxLines:3
,TextField 默认显示 2 行,可以从第一行输入,连续输入三行,,超过 三行,坚向滚动。
如果设置了 minLines,必须同时设置 maxLines。
自定义验证
abstract class TextInputFormatter {TextEditingValue formatEditUpdate(TextEditingValue oldValue,TextEditingValue newValue,);static TextInputFormatter withFunction(TextInputFormatFunction formatFunction,) {return _SimpleTextInputFormatter(formatFunction);}
}
TextInputFormatter 是一个抽象类,当需要定义自己的子类的时候,只需要 override formatEditUpdate 方法。formatEditUpdate 可以修改 text 的值,比如禁止不被允许的值。 withFunction 是一个快捷函数,让我们直接定义 text 的逻辑,而不必定义新的类。
比如只允许输入 0-9
TextField(inputFormatters: [TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) {return RegExp(r'^[0-9]*$').hasMatch(newValue.text)? newValue: oldValue;},),],
);
如果再限制一下长度这样写RegExp(r'^[0-9]{0,10}$')
,只能输入 0 到 10 个数字。
Flutter 为 TextInputFormatter 实现了两个子类,我们可以直接用。
FilteringTextInputFormatter
LengthLimitingTextInputFormatter
TextField 的 maxLength 功能就是用 LengthLimitingTextInputFormatter 实现的。
FilteringTextInputFormatter 用来过滤字符。
FilteringTextInputFormatter(this.filterPattern, {required this.allow,this.replacementString = '',});
filterPattern 我们一般用 RegExp,就是正则来判断是否匹配。allow 如果为 true,filterPattern 是用于匹配合法的文本,如果为 false,匹配非法的文本。replacementString 是用来替换非法文本的替换字符串。
FilteringTextInputFormatter 有两个命名构造函数,对 allow 进行了赋值,一般情况下,我们优先使用这两个构造函数,让代码更可读。
FilteringTextInputFormatter.allow(Pattern filterPattern, {String replacementString = '',}) : this(filterPattern, allow: true, replacementString: replacementString);FilteringTextInputFormatter.deny(Pattern filterPattern, {String replacementString = '',}) : this(filterPattern, allow: false, replacementString: replacementString);
举个例子,只允许输入 0-9
TextField(inputFormatters: [FilteringTextInputFormatter.allow(RegExp('r[0-9]'))],
);
再比如不允许输入 x
TextField(inputFormatters: [FilteringTextInputFormatter.deny(RegExp('x'))],);
你可能疑问 deny 的参数不是 Patten 吗?怎么能输入字符串?答案是 String 实现了 Patten 接口
abstract class String implements Comparable<String>, Pattern
替换的功能就不举例子了,可以自己试试。如果需要替换的时候,优先考虑用 FilteringTextInputFormatter。
如果你的验证逻辑很常用,可以 extends 一个子类出来,把逻辑封装起来。还是用只能输入 0-9
这个例子:
class MyFormatter extends TextInputFormatter {@overrideTextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {return RegExp(r'^[0-9]*$').hasMatch(newValue.text) ? newValue : oldValue;}
}
用的时候就会很方便
TextField(inputFormatters: [MyFormatter()],
);
onEditingComplete 与 onSubmitted
这两个事件是同时触发的,onEditingComplete 在前,onSubmitted 在后。
如果 onEditingComplete 不设置,默认可能让 TextField 失去焦点。如果不为空,就走 onEditingComplete 的逻辑。
onSubmitted 可以获得 TextFile 的 text。
在下面的例子中,虽然 onEditingComplete 函数体为空,但毕竟不是 null,成功阻止了默认的可能让 TextField 失去焦点的行为。在 onSubmitted 中可以打印 TextField 中的文本。
TextField(onEditingComplete: () {},onSubmitted: (value) {print(value);},
);
选中文本
选中文本 还是比较简单的,指定 TextSelection 的开始位置 baseOffset,和结束位置 extentOffset 即可。
下面的例子中,点击按钮会选中全部已经输入的文本。
Column(children: [TextField(controller: controller,style: const TextStyle(color: Color(0xFFC45F84), fontSize: 24),),ElevatedButton(onPressed: () {controller.selection = TextSelection(baseOffset: 0, extentOffset: controller.text.length);},child: Text('选中全部文本'))],
);
最后要了解的是 当 TextField 获得焦点时,它会阻止自己通过 AutomaticKeepAliveClientMixin.wantKeepAlive 进行 dispose,以避免丢失 selection。移除焦点将允许它被disposed。
Flutter TextField 交互实例 到这里就结束了,谢谢观看。
Flutter TextField 交互实例 —— 新手礼包相关推荐
- Flutter Row 实例 —— 新手礼包
大家好,我是 17. 本文在 3.31 日全站综合热榜第一. 新手礼包一共 3 篇文章,每篇都是描述尽量详细,实例讲解,包会! Flutter Row 实例 -- 新手礼包 Flutter TextF ...
- flutter TextField 属性详细分析
flutter TextField 属性 简单的进行了归纳,有些是仅凭字面翻译. flutter TextField中的InputDecoration属性 TextField({Key key,thi ...
- flutter TextField 输入框被软键盘挡住的解决方案
flutter TextField 输入框被软键盘挡住的解决方案 参考文章: (1)flutter TextField 输入框被软键盘挡住的解决方案 (2)https://www.cnblogs.co ...
- Vue前后台数据交互实例演示,使用axios传递json字符串、数组
Vue 前后台数据交互实例演示 第一章:后台实现 ① Python 启用 Flask 服务器 ② 后台启用成功验证 第二章:前台实现 ① Vue 使用 Axios 实现接收 json 字符串.数组数据 ...
- php安卓交互安全,php结合安卓客户端实现查询交互实例
本文给大家分享的是php结合安卓客户端实现查询交互实例,java端主要分三步来实现:首先进行 http request.网络请求相关操作,第二步,使用execute方法发送HTTP GET请求,并返回 ...
- Flutter TextField 设置默认值和光标位置
Flutter TextField 是一个文本输入框,可以结合使用 TextEditingController 来获取输入框中的内容以及设置 TextField 中默认显示的内容 TextEditin ...
- pyqt5多进程 python_PYQT5开启多个线程和窗口,多线程与多窗口的交互实例
每点击一次按钮,弹出一个对话框(子窗口),同时开启一个子线程来执行任务并更新对话框内容,关闭对话框则关闭对应子线程 1. 建立一个简单的主界面和一个自定义对话框 from PyQt5 import Q ...
- PHP JSON格式数据交互实例代码详解_php技巧_脚本之家
http://www.jb51.net/article/26007.htm 此前我写了不少在PHP网站开发中应用XML进行数据交互的实例,这两天通过PHP解析JSON并进行交互的实例学习和了解了JSO ...
- java jqgrid_jqgrid 前后端交互实例
原标题:jqgrid 前后端交互实例 首先,jqGrid 是一个用来显示网格数据的jQuery插件,通过使用jqGrid可以轻松实现前端页面与后台数据的ajax异步通信. 一.jqGrid特性 基于j ...
最新文章
- [转]hibernate------HQL总结
- sharding jdbc:分库、分表;读写分离;
- 数据流DataInput(Output)Stream 和 字节数组流 ByteArrayInput(Output) Stream
- 互联网职场就像一场《鱿鱼游戏》
- 让你少写 1000 行代码的正则全攻略来了!
- pmp每日三题(2022年2月22日)
- 显示三维图片序列_SLAM结合三维检测
- 深度相机(三)--三种方案对比
- .NET中的异步编程(一)-为什么需要异步
- Myeclipse7.X和8.X汉化
- Oracle管理文件OMF (oracle managed files)
- php是日元吗,PHP to JPY
- carto笔记--- 传感器数据走向
- eas账号是什么意思_请问帐号和账号有什么区别,具体怎么用?
- 跟张志东深聊,腾讯的“进化力”
- 如何在远程桌面无响应的情况下完成远程电脑重启
- spark kryo java_Spark 配置Kryo序列化机制
- 不要瞎折腾,几张思维导图就讲清搜索引擎优化(SEO)核心点
- 沈南鹏@《遇见大咖》: A轮没投,投了8个月以后就证明了张一鸣是对了,在美国都没有张一鸣这种模式...
- Docker基础笔记(狂神说)
热门文章
- 计算机网络——NAT协议
- JAVA 分支结构 swit结构 for循环
- [6 kyu] Playing with digits
- topaz sharpen ai2直装版(图像锐化工具) v2.1.8
- Qt5气泡式聊天框,QT聊天软件
- 动手学深度学习V2.0(Pytorch)——23. LeNet(mnist)
- 频繁刷机,今日刷机为1.30.111WWE
- 虚幻4皮肤材质_UE4实时虚拟角色材质篇之Skin Material(二)面部动画贴图融合
- webpack 之vue 初级打包1 从零开始
- 安徽省引进 AI 建设首家智慧肿瘤医院;商汤携手海航,突破 AI+场景视界