(Flutter) Как автоматически прослушать изменения в текстовом поле, не нажимая «Готово»?

#dart #flutter

#dart #flutter

Вопрос:

Я печатаю ввод из текстового поля в диалоговом окне (и текстовое поле, и вывод находятся в AlertDialog). Вывод обновляется только тогда, когда я нажимаю «Готово» на клавиатуре. Если я не нажимаю «Готово», он продолжает показывать мне старый вывод.

Вот мой исходный код:

 Future<void> widePopUpCustom() async {
  return showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
            title: Text('Enter Number'),
            content: SingleChildScrollView(
                child: ListBody(children: <Widget>[
              TextField(
                  controller: customRun,
                  decoration: InputDecoration(
                    labelText: 'Number',
                  )),
              Text('${customRun.text}'),
            ])),
            actions: <Widget>[
              FlatButton(
                  child: Text('OK'), onPressed: () => Navigator.pop(context))
            ]);
      });
}
  

Я тоже объявил контроллер:

   final TextEditingController customRun = TextEditingController();
  

(Дальнейшее разъяснение) Это мой вывод, который я хочу обновлять в режиме реального времени при вводе текста в моем текстовом поле, не нажимая «Готово» на клавиатуре

  Text('${customRun.text}'), 
  

Ответ №1:

Демонстрационный вариант вы можете посмотреть здесь. Пример

1. Определите текстовый виджет, который нуждается в перестройке

Сначала мы ожидаем, что содержимое внутри этого виджета будет перестроено в соответствии с пользовательскими типами.

 Text('${customRun.text}'),
  

К сожалению, этот виджет находится внутри метода widePopUpCustom как
Дочерние элементы диалогового окна оповещения

 void widePopUpCustom() async {
    await showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Enter Number'),
          content: SingleChildScrollView(
            child: ListBody(
              children: <Widget>[
                TextField(
                  controller: customRun,
                  decoration: InputDecoration(
                    labelText: 'Number',
                  ),
                ),
                Text('${customRun.text}'), // Needs to be re-rendered
              ],
            ),
          ),
        );
      },
    );
  }
  

в этом случае мы не можем запустить перестроение для AlertDialog виджета, включая все его дочерние элементы, ListBody , TextField и Text виджет.

2. Разделите AlertDialog и преобразуйте его в виджет с отслеживанием состояния

Мы рассматриваем возможность перехода AlertDialog в AlertWrapper и определяем AlertWrapper как виджет с отслеживанием состояния. Таким образом, позже мы сможем запустить перестроение AlertWrapper , используя этот код :

 setState((){})
  

Мы можем завершить этот шаг, как изменение widePopUpCustom() этого :

 Future<void> widePopUpCustom() async {
    return showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        return AlertWrapper();
      },
    );
  }
  

Ранее AlertDialog считался не имеющим состояния, которое не будет повторно отображено, пока мы не закроем диалоговое окно.

3. Переопределите виджет с отслеживанием состояния, чтобы подключить прослушиватель

Используя виджет с отслеживанием состояния, мы можем изучить использование initState. В этом случае мы подключаемся addListener к customRun TextController.

Пожалуйста, обратите внимание на метод changesOnField. Этот метод будет срабатывать каждый раз, когда пользователь взаимодействует с вводом с клавиатуры

 class AlertWrapper extends StatefulWidget {
  const AlertWrapper({
    Key key,
  }) : super(key: key);

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

class _AlertWrapperState extends State<AlertWrapper> {
  final TextEditingController customRun = TextEditingController();

  changesOnField() { 
    print("Updated Text: ${customRun.text}");
    setState(() {}); // Will re-Trigger Build Method
  }

  @override
  void initState() {
    super.initState();
    customRun.addListener(changesOnField);
  }
}
  

changesOnField вызовет повторный вызов метода сборки, и тогда мы сможем обновить наше значение внутри текстового виджета

 @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('Enter Number'),
      content: SingleChildScrollView(
        child: ListBody(
          children: <Widget>[
            TextField(
              controller: customRun,
              decoration: InputDecoration(
                labelText: 'Number',
              ),
            ),
            Text('${customRun.text}'), // Finally re-rendered
          ],
        ),
      ),
  

Полностью работающий репозиторий

Вы можете посмотреть этот репозиторий. Github

Другие улучшения

Как указано в официальных документах, нам нужно настроить прослушиватель для оптимизации приложения.

позже мы сможем добавить этот код

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

Ответ №2:

вам нужно добавить onChanged(txt) метод для текстового поля, и он должен содержать setState() внутри, чтобы текст обновлялся каждый раз, когда вы вводите символ

 Future<void> widePopUpCustom() async {
  return showDialog<void>(
  context: context,
  builder: (BuildContext context) {
    return AlertDialog(
        title: Text('Enter Number'),
        content: SingleChildScrollView(
            child: ListBody(children: <Widget>[
          TextField(
              controller: customRun,
              decoration: InputDecoration(
                labelText: 'Number',
              )),
              onChanged:(txt){
                 setState((){
                   customRun.text = txt;
                 }),    
                 },
          Text('${customRun.text}'),
        ])),
        actions: <Widget>[
          FlatButton(
              child: Text('OK'), onPressed: () => Navigator.pop(context))
        ]);
  });
  

}

Комментарии:

1. Он по-прежнему не обновляет выходные данные в режиме реального времени. Обновление происходит только тогда, когда я нажимаю «Готово» на клавиатуре. Просто уточнение: Текст (‘${customRun.text}’), это мой вывод

2. я рекомендую вам добавить новую строковую переменную для хранения входных данных и вывода ее в текстовом представлении, я использую ее довольно часто, и она работает и обновляется для каждой добавленной буквы