flutter - Flutter Newbie:修改 Textfield 值打破对 TextField 的关注
问题描述
放轻松。我一周前才开始学习 Flutter。我来自 ReactJS,所以我对状态管理和生命周期方法有很好的理解。但我对 Dart 和 Flutter 以及它如何处理状态完全陌生。
我正在编写一个快速的 WebRTC 聊天应用程序。我有一个用来生成房间名称的 TextField。我决定要制作 TextField 的 labelText,每 5 秒循环一些随机单词,而该字段不在焦点上。如果该领域成为焦点,我停止循环标签。我这样做是为了使该字段看起来有一个预先生成的随机房间名称。
我在编辑 TextField 时遇到问题。我认为这是 setState 或我的 TextEditingController 的问题。我习惯于能够访问输入的值,所以控制器对我来说很奇怪。
这是我的更改文本字段:
import 'dart:async';
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
//
class ChangingTextField extends StatefulWidget {
final TextEditingController controller;
ChangingTextField({
Key? key,
required this.controller,
}) : super(key: key);
@override
_ChangingTextFieldState createState() => _ChangingTextFieldState();
}
class _ChangingTextFieldState extends State<ChangingTextField> {
FocusNode _focusNode = FocusNode();
Timer? _timer;
String _roomName = "example.com/";
bool _wasFocused = false;
@override
void initState() {
super.initState();
_focusNode = FocusNode();
_timer = Timer.periodic(Duration(seconds: 5), (Timer t) => _genRoomName());
}
@override
void dispose() {
_timer?.cancel();
_focusNode.dispose();
super.dispose();
}
void _requestFocus(){
if(!_wasFocused){
setState(() {
_timer?.cancel();
_wasFocused = true;
FocusScope.of(context).requestFocus(_focusNode);
});
}
}
void _genRoomName(){
WordPair wp = generateWordPairs().take(1).first;
setState(() => _roomName = "example.com/" + wp.first + "-" + wp.second );
}
@override
Widget build(BuildContext context) {
return Container(
child: TextField(
focusNode: _focusNode,
controller: widget.controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: _wasFocused ? "example.com/" : _roomName,
),
onTap: _requestFocus,
),
);
}
}
父小部件只是将 TextEditingController 传递到此小部件中,以便我可以监听更改,并且(我假设)在稍后的时间点收集 TextField 的值。
侦听器在父小部件中定义如下:
@override
void initState() {
roomNameController.addListener(() {
setState(() {});
});
super.initState();
}
但是,每次我尝试更改 TextField 的值时,在我键入每个字符之后,焦点都会在 ChangingTextField 小部件上中断,我必须在 TextField 内再次单击以键入我的下一个字符。我假设这个问题是因为侦听器在父小部件中调用 setState。
在 React 术语中,我将其称为重新渲染。如果父级重新渲染,子级会随之而去,因此应用程序会丢失它所拥有的关于用户在小部件树中工作的位置的知识。但是,我觉得控制器需要存在于父级中,这样,我可以在需要时(例如按下按钮)获取子级的值。提升状态等等。
有人可以向我解释这里发生了什么吗?
解决方案
我找到了解决方案。在小部件内部进行侦听而不是在父组件中初始化侦听器会产生您期望的行为。
简而言之,移动以下代码:
@override
void initState() {
roomNameController.addListener(() {
setState(() {});
});
super.initState();
}
进入ChangingTextField 小部件的initState 而不是将其置于父级的initState 中,解决了这个问题。最重要的是,控制器仍然由父级创建,因此当按下提交按钮时,控制器的文本在父级中可用。
推荐阅读
- fabric8 - Fabric8 Maven 插件 - 如何将 --rm 传递给构建选项?
- php - 如何在 web.php 中定义路由以在 Laravel 中显示 404 视图?
- c++ - node-gyp build 给出未解决的外部符号错误
- .net - Azure Function V2 - 错误:与服务器的连接异常终止
- php - 基于类别顺序在 laravel eloquent 关系中获得一行的特定类别中有多少张图像?
- asp.net - 如何从 ASP.NET 页面返回 JSON 值
- laravel - 在 Laravel Blade 文件中的多个数组上使用 foreach 循环对齐 UI 元素时出现问题
- spring - 原生查询结果映射到spring jpa中的自定义对象
- c# - 使用 ms 访问从 MemoryStream 读取位图时抛出异常
- javascript - java脚本嵌套过滤函数