flutter - 每次屏幕发生变化时都会调用屏幕的构造函数
问题描述
当textformfield
在推送的屏幕中点击 a 时,屏幕的构造函数会再次被调用,并且textformfield
会失去它的值。另外,我认为该屏幕中发生的每次更改都会导致再次调用其构造函数,而我根本不知道原因。
这是生成错误的示例代码:
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Hello',
style: TextStyle(color: Colors.black, fontSize: 30.0),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => NextScreen(Bloc())));
},
child: Icon(Icons.add),
),
);
}
}
这是要推送的屏幕
class NextScreen extends StatefulWidget {
final _bloc;
NextScreen(this._bloc);
@override
_NextScreenState createState() => _NextScreenState();
}
class _NextScreenState extends State<NextScreen> {
@override
void dispose() {
widget._bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(100.0),
child: IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: Icon(Icons.arrow_back),
iconSize: 20.0,
),
),
StreamBuilder<String>(
stream: widget._bloc.stream,
builder: (context, snapshot) {
return TextFormField(
controller: widget._bloc.controller,
onFieldSubmitted: widget._bloc.submitData(),
decoration: InputDecoration(
hintText: 'Enter your name..',
errorText: snapshot.data,
),
);
})
],
),
);
}
}
验证用户输入的块
class Bloc {
TextEditingController _controller;
TextEditingController get controller => _controller;
BehaviorSubject<String> _subject;
BehaviorSubject<String> _validatorSubject;
Stream<String> get stream => _validatorSubject.stream;
void submitData() {
_subject.sink.add(controller.text);
}
void _validate(String text) {
if (!RegExp(r'[0-9]').hasMatch(text)) {
_validatorSubject.sink.add('numbers only');
} else {
_validatorSubject.sink.add(null);
}
}
Bloc() {
_controller = TextEditingController();
_subject = BehaviorSubject<String>();
_validatorSubject = BehaviorSubject<String>();
_subject.stream.listen(_validate);
}
void dispose() {
_subject.close();
_validatorSubject.close();
}
}
解决方案
打开和关闭键盘将重建整个屏幕。真正的罪魁祸首是 textController :
controller: widget._bloc.controller,
对我有用的解决方案是删除这条线。
此外,要获取和验证更改的文本,您可以在文本字段中使用 onChanged,它会返回一个字符串。像这样 :
.
.
.
return TextFormField(
onChanged: widget._bloc.submitData,
decoration: InputDecoration
.
.
.
你 submitData() 方法会是这样的:
void submitData(String data) {
_subject.sink.add(data);
}
推荐阅读
- flutter - 重新加载小部件树时未重新创建颤振 BlocProvider
- python - 为什么我的函数在通过 if 语句时不起作用?
- java - while((message = reader.readLine()) != null) 是无限循环吗?
- javascript - 如何将文本文件读入 JavaScript 中的对象数组
- javascript - Quill 富文本编辑器:如何将文件输入按钮附加到工具栏并嵌入到编辑器
- javascript - 如何设置状态
- linux - Logstash 在 Ubuntu 中没有显示任何输出
- google-apps-script - 谷歌脚本 DriveApp.getFolders().hasNext() 错误
- javascript - 同时更改范围滑块和输入框的值
- javascript - 谷歌翻译、必应翻译等网站如何工作?