[Flutter]解决RFID阅读器读取的数据在TextField中显示不全的问题
问题及原因分析
RFID 阅读器在读取到数据后,会寻找具有焦点的 TextField
,并将读取到的数据输出到 TextField
中,之后发送一个回车按键事件。
这里有个问题,不能使用 TextField
的 onChanged
方法来获取输入框中的文字,因为此事件会触发多次。也不能使用 onEditingComplete
或者 onSubmitted
,因为在 TextField
接收完数据之前,就会触发回车键,导致 TextField
失去焦点,并中断接收数据。至于为什么回车事件会先于数据接收完成之前执行,我猜测,大概是因为不断重建 TextField
Widget 的过程消耗了太多时间,同时 Flutter 内部存在一个类似 JavaScript 的事件循环机制,导致回车事件排在了接下来的 onChanged
事件之前。说实话,我是一个初学者,对 Flutter 了解不够深入。
解决思路
想要解决这个问题,貌似不能从 TextField
本身的属性配置上来下手了。既然 TextField
接收数据有延迟,那就需要定时检测 TextField
关联的 TextEditingController.text
在一定时间内是否还会变化,根据变化情况来确定数据是还在接收,还是已经接收完毕。
焦点的问题
在实现上面的定时检测代码之前,还有一个问题需要解决:焦点问题。上文提到了,TextField
在没接收完数据之前就会触发回车事件并失去焦点。一旦 TextField
失去焦点,便不再接收剩余的数据。经过不断尝试,将 TextField
的 keyboardType
设置为 TextInputType.multiline
能够解决这个问题。
以下是官方文档对 TextInputType.multiline
的解释:
Optimize for multiline textual information.
Requests the default platform keyboard, but accepts newlines when the enter key is pressed. This is the input type used for all multiline text fields.
优化多行文本信息。
请求默认平台键盘,但按下enter键时接受换行。这是用于所有多行文本字段的输入类型
但设置了这一属性,TextField
里面的文字在遇到回车时不就换行了吗?没有关系,只要我们不设置它的 maxLines
属性为 1
以外的值,这就不会发生。maxLines
的默认值就是 1
,所以,总而言之,我们只要设置 keyboardType
属性为 TextInputType.multiline
就行了,无需考虑其他问题。
定时检测的实现
下面需要一个定时器来检测 TextField
的内容。核心思想是,定时检查 TextField
的 TextEditingController.text
的值是否与上一次保存的旧值相同,如果不同,说明接收仍在继续,这时要将新值保存起来,用于下一次对比。如果新值和旧值相同,就认为数据接收已经完毕。
代码如下:
final inputController = TextEditingController();
Timer? timer;
int count = 0; //设置了一个定时器执行次数
String oldVal = '';
timer = Timer.periodic(const Duration(milliseconds: 500), (_timer) async {
if (
count >= 10 ||
(
inputController.text != '' &&
oldVal != '' &&
inputController.text == oldVal
)
) {
_timer.cancel();
//do something you want...
} else {
count++;
oldVal = inputController.text;
}
});
END