#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. я рекомендую вам добавить новую строковую переменную для хранения входных данных и вывода ее в текстовом представлении, я использую ее довольно часто, и она работает и обновляется для каждой добавленной буквы