[英]Flutter: Update TextFormField text with ChangeNotifier
In a complex scenario I need to update the text of some TextFormField
s when a notifyListeners()
is sent by a Model extending ChangeNotifier
.在复杂的场景中,当扩展ChangeNotifier
的模型发送notifyListeners()
时,我需要更新某些TextFormField
的文本。 The problem is that to change the text of a TextFormField
you have to use the setter TextFormField.text
which implies a rebuild, and so you can't use it into the build
method.问题是要更改TextFormField
的文本,您必须使用 setter TextFormField.text
这意味着重建,因此您不能将其用于build
方法。 But to access the Provider
of the model you need the context
which is inside the build
method.但是要访问模型的Provider
,您需要build
方法中的context
。
MWE (obviously the button is in another Widget in the real project, and there are more TextFormField
s) MWE(很明显按钮在真实项目中的另一个Widget中, TextFormField
比较多)
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyModel extends ChangeNotifier {
void updateCounter() {
++_counter;
notifyListeners();
}
MyModel() {
_counter = 1;
}
int _counter;
String get counter => _counter.toString();
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => MyModel(),
child: MaterialApp(
title: 'Test',
home: MyHomePage(),
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _text1Ctl = TextEditingController();
var _text2Ctl = TextEditingController();
@override
void initState() {
super.initState();
final model = MyModel();
model.addListener(() {
_text1Ctl.text = model.counter;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
FlatButton(
onPressed: () {
Provider.of<MyModel>(context, listen: false).updateCounter();
},
child: Text('Press me'),
),
// 1st attempt
// Doesn't work because the listener isn't applied to the instance of the model provided by the provider.
TextFormField(controller: _text1Ctl),
// 2nd attempt
// Works but with `Another exception was thrown: setState() or markNeedsBuild() called during build.` because it changes text via controller (which implies a rebuild) during building.
Consumer<MyModel>(builder: (context, model, child) {
_text2Ctl.text = model.counter;
return TextFormField(controller: _text2Ctl);
})
]));
}
}
Your second example works without any errors when I run it:你的第二个例子在我运行时没有任何错误:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyModel extends ChangeNotifier {
void updateCounter() {
++_counter;
notifyListeners();
}
MyModel() {
_counter = 1;
}
int _counter;
String get counter => _counter.toString();
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => MyModel(),
child: MaterialApp(
title: 'Test',
home: MyHomePage(),
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _text2Ctl = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
FlatButton(
onPressed: () {
Provider.of<MyModel>(context, listen: false).updateCounter();
},
child: Text('Press me'),
),
// 2nd attempt
// Works but with `Another exception was thrown: setState() or markNeedsBuild() called during build.` because it changes text via controller (which implies a rebuild) during building.
Consumer<MyModel>(builder: (context, model, child) {
_text2Ctl.text = model.counter;
return TextFormField(controller: _text2Ctl);
})
]));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.