在复杂的情况下,当扩展TextFormField
的模型发送notifyListeners()
时,我需要更新某些ChangeNotifier
的文本。
问题是要更改TextFormField
的文本,您必须使用setter TextFormField.text
,这意味着要进行重建,因此不能在build
方法中使用它。但是要访问模型的Provider
,您需要context
方法内部的build
。
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);
})
]));
}
}
答案 0 :(得分:1)
您运行的第二个示例在运行时没有任何错误:
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);
})
]));
}
}