Flutter: как получить текст из TextEditingController в настраиваемом StatefulWidget?

Я пытаюсь заставить настраиваемый виджет с отслеживанием состояния работать во флаттере. Он называется LetterTextForm и содержит некоторые настройки макета и TextField.

Я хочу, чтобы было легко получить текст, введенный в TextField виджета, с помощью какого-то метода получения в теле виджета, который возвращает TextEditingController.text. Проблема в том, что когда я делаю контроллер TextEditingController последней переменной следующим образом:

class LetterTextForm extends StatefulWidget {

  LetterTextForm({@required this.label, this.prefixIcon});
  final Widget prefixIcon;
  final String label;
  final TextEditingController controller = TextEditingController();
  String get textEntered => controller.text;


  @override
  _LetterTextFormState createState() => _LetterTextFormState();
}

class _LetterTextFormState extends State<LetterTextForm> {
  

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
  controller.dispose();
    super.dispose();
  }


  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: widget.controller,
        decoration: InputDecoration(
          prefixIcon: widget.prefixIcon,
          labelText: widget.label,
        )
    );
  }
}


возникает следующая ошибка: TextEditingController использовался после удаления.

Я подумал, что, возможно, проблема в том, что контроллер не должен быть окончательным, поэтому я переместил контроллер в класс состояния и сделал функцию в классе состояния textCallback, которая изменяет неокончательную строку, которая находится в классе виджета. Этот способ работает, но нарушает неизменяемость виджета:


class LetterTextForm extends StatefulWidget {

  LetterTextForm({@required this.label, this.prefixIcon});
  final Widget prefixIcon;
  final String label;
  String text = '';

  String get textEntered => text;



  @override
  _LetterTextFormState createState() => _LetterTextFormState();
}

class _LetterTextFormState extends State<LetterTextForm> {
  var controller = TextEditingController();
  
  void textCallback() {
    widget.text = controller.text;
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
  controller.dispose();
    super.dispose();
  }


  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: controller,
        decoration: InputDecoration(
          prefixIcon: widget.prefixIcon,
          labelText: widget.label,
        )
    );
  }
}


Есть ли способ сделать это, что и 1) не нарушает неизменяемость, и 2) не удаляет TextEditingController () сразу же, когда пользователь нажимает Enter?

Он работает, когда я избавляюсь от метода dispose (), но похоже, что позже это может вызвать некоторые проблемы с производительностью / эффективностью памяти. Может, я не понимаю, о чем там говорю ...

Возможно, мне стоит попробовать что-то совершенно другое и разместить TextEditingControllers дальше в дереве с предками виджета LetterTextForm, а не внутри виджета?


person Jackson    schedule 24.12.2020    source источник


Ответы (1)


Создайте ValueChanged<String> член обратного вызова и перезвоните ему, когда данные будут завершены.

class LetterTextForm{
  ...
  final ValueChanged<String> onChanged;
  ...
}

class _LetterTextFormState extends ... {
  final _controller = TextEditingController();
  
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(...) {
    return TextField(
      controller: _controller,
      onSubmitted: (value) {
        if (widget.onChanged != null) {
          widget.onChanged(value); // returns entered value to caller
        }
      },
    );
  }
}

P.S. Если использовать TextFormField, то контроллер не нужен, и вы можете использовать initialData для инициализации.

person BambinoUA    schedule 25.12.2020