首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Flutter新手:修改TextField值会中断Textfield

Flutter新手:修改TextField值会中断Textfield
EN

Stack Overflow用户
提问于 2021-08-25 18:43:42
回答 1查看 37关注 0票数 0

放轻松。我一周前才开始学习Flutter。我来自ReactJS,所以我对状态管理和生命周期方法有一个很好的理解。但我对Dart和Flutter以及它是如何处理状态的完全陌生。

我正在写一个快速的WebRTC聊天应用程序。我有一个用来生成房间名称的TextField。我决定制作TextField的labelText,在字段不在焦点的情况下,每隔5秒循环一些随机的单词。如果该字段成为焦点,我将停止循环该标签。我这样做是为了让字段看起来有一个预先生成的随机房间名称。

我在编辑TextField时遇到问题。我假设这是setState或我的TextEditingController的问题。我习惯于访问输入值,所以控制器对我来说很奇怪。

这是我的ChangingTextField:

代码语言:javascript
复制
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的值。

在父小部件中,侦听器的定义如下:

代码语言:javascript
复制
  @override
  void initState() {
    roomNameController.addListener(() {
      setState(() {});
    });
    super.initState();
  }

但是,每次我尝试更改TextField的值时,在我键入的每个字符之后,焦点都会转移到ChangingTextField小部件上,我必须再次在TextField内部单击才能键入下一个字符。我假设这个问题是因为侦听器在父小部件中调用了setState。

在React术语中,我将其称为重新呈现。如果父对象重新渲染,子对象也会随之呈现,因此应用程序将丢失它所知道的用户在窗口小部件树中的位置。但是,我觉得控制器需要存在于父元素中,这样,我就可以在需要的时候(例如按下按钮)获取子元素的值。提升状态,诸如此类。

有人能给我解释一下这是怎么回事吗?

EN

回答 1

Stack Overflow用户

发布于 2021-08-25 22:26:36

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

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

代码语言:javascript
复制
  @override
  void initState() {
    roomNameController.addListener(() {
      setState(() {});
    });
    super.initState();
  }

在ChangingTextField小部件的initState中,而不是在父部件的initState中,解决了这个问题。最棒的是,控制器仍然是由父级创建的,所以当按下submit按钮时,控制器的文本在父级中可用。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68928313

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档