Flutter Newbie:修改 Textfield 值打破对 TextField 的关注

Posted

技术标签:

【中文标题】Flutter Newbie:修改 Textfield 值打破对 TextField 的关注【英文标题】:Flutter Newbie: Modifying Textfield value breaks focus on TextField 【发布时间】:2021-10-25 21:53:24 【问题描述】:

轻松一点。我一周前才开始学习 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 术语中,我将其称为重新渲染。如果父级重新渲染,子级会随之而去,因此应用程序会丢失它所拥有的关于用户在小部件树中工作的位置的知识。但是,我觉得控制器需要存在于父级中,这样,我可以在需要时(例如按下按钮)获取子级的值。提升状态等等。

谁能给我解释一下这里发生了什么?

【问题讨论】:

【参考方案1】:

我找到了解决方案。在小部件内部进行侦听而不是在父组件中初始化侦听器会产生您所期望的行为。

简而言之,移动如下代码:

  @override
  void initState() 
    roomNameController.addListener(() 
      setState(() );
    );
    super.initState();
  

进入ChangingTextField 小部件的initState,而不是将它放在父级的initState 中,解决了这个问题。最重要的是,控制器仍然是由父级创建的,因此当按下提交按钮时,控制器的文本在父级中是可用的。

【讨论】:

以上是关于Flutter Newbie:修改 Textfield 值打破对 TextField 的关注的主要内容,如果未能解决你的问题,请参考以下文章

新手:如何在 Flutter 中添加多个 Listtile

无标题

NEWBIE #1064 - 你的 SQL 语法有错误

Newbie-X之个人代码仓库介绍

CodeForces 312BBUPT 2015 newbie practice #3A Archer

Newbie Python生成1到10之间的平方和