放轻松。我一周前才开始学习Flutter。我来自ReactJS,所以我对状态管理和生命周期方法有一个很好的理解。但我对Dart和Flutter以及它是如何处理状态的完全陌生。
我正在写一个快速的WebRTC聊天应用程序。我有一个用来生成房间名称的TextField。我决定制作TextField的labelText,在字段不在焦点的情况下,每隔5秒循环一些随机的单词。如果该字段成为焦点,我将停止循环该标签。我这样做是为了让字段看起来有一个预先生成的随机房间名称。
我在编辑TextField时遇到问题。我假设这是setState或我的TextEditingController的问题。我习惯于访问输入值,所以控制器对我来说很奇怪。
这是我的ChangingTextField:
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术语中,我将其称为重新呈现。如果父对象重新渲染,子对象也会随之呈现,因此应用程序将丢失它所知道的用户在窗口小部件树中的位置。但是,我觉得控制器需要存在于父元素中,这样,我就可以在需要的时候(例如按下按钮)获取子元素的值。提升状态,诸如此类。
有人能给我解释一下这是怎么回事吗?
发布于 2021-08-25 22:26:36
我找到了解决方案。在小部件内部进行侦听,而不是在父组件中初始化侦听器,会产生您所期望的行为。
简而言之,移动以下代码:
@override
void initState() {
roomNameController.addListener(() {
setState(() {});
});
super.initState();
}在ChangingTextField小部件的initState中,而不是在父部件的initState中,解决了这个问题。最棒的是,控制器仍然是由父级创建的,所以当按下submit按钮时,控制器的文本在父级中可用。
https://stackoverflow.com/questions/68928313
复制相似问题