[英]How to TextFormField in flutter when state changes, using Provider/ChangeNotifier?
I have an issue with updating text inside TextFormField
when using Provider as state management.使用 Provider 作为状态管理时,我在更新
TextFormField
中的文本时遇到问题。
I reduced my problem to abstract one (I removed all the clutter code) and here how it works:我将我的问题简化为抽象问题(我删除了所有杂乱的代码)以及它是如何工作的:
someValue
in AppState
AppState
中有一个someValue
someValue
can be edited via Form->TextFormField
someValue
可以通过Form->TextFormField
进行编辑someValue
is to be reflected as a title of the AppBar when typing ( onChange
) someValue
将在键入时反映为 AppBar 的标题( onChange
)someValue
can be updated from external source (in the example it is a button that updates it) someValue
可以从外部源更新(在示例中它是一个更新它的按钮)someValue
is updated from external source , it MUST be updated in text Form->TextFormField
as wellsomeValue
从外部源更新时,它也必须在文本Form->TextFormField
中更新The last one is causing me the problem.最后一个是导致我的问题。 Consider following code:
考虑以下代码:
AppState.dart AppState.dart
import 'package:flutter/foundation.dart';
class AppState extends ChangeNotifier
{
String someValue = '';
updateSomeValue(String newValue)
{
someValue = newValue;
notifyListeners();
}
}
main.dart主要.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:text_ctrl_issue/app_state.dart';
void main() {
runApp(ChangeNotifierProvider(create: (_) => AppState(), child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
late TextEditingController _controller;
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
_controller = TextEditingController();
}
@override
Widget build(BuildContext context) {
final provider = Provider.of<AppState>(context);
// following line of code makes it possible for text to be changed by button
// and reflected in TextFormField
// but it causes nasty side effect, that when typing, cursor always goes to beginning of the line
_controller.text = provider.someValue;
return Scaffold(
appBar: AppBar(
title: Text(provider.someValue),
),
body: Center(
child: Form(
key: _formKey,
child: Column(children: [
TextFormField(
controller: _controller,
onChanged: (v) {
provider.updateSomeValue(v);
},
),
ElevatedButton(
onPressed: () {
provider.updateSomeValue('foo_bar');
},
child: Text('change text external source'))
])),
),
);
}
}
The problem: When I added the line _controller.text = provider.someValue;
问题:当我添加行
_controller.text = provider.someValue;
it fixed the issue of updating TextFormField when button is clicked, but it create new issue, that when typing in TextFormField, it is also triggered, cause carret of text field to move to the beginning of the text field.它修复了单击按钮时更新 TextFormField 的问题,但它创建了新问题,即在 TextFormField 中键入时,它也会被触发,导致文本字段的 carret 移动到文本字段的开头。
How to make it work so text (value) of a TextFormField can be updated externally, without causing carret
issue when typing?如何使其工作,以便可以在外部更新 TextFormField 的文本(值),而不会在键入时引起
carret
问题?
EDIT Answer of Yeasin Sheikh using addListener
doesn't quite work (it is hacky) because:使用
addListener
编辑Yeasin Sheikh 的答案不太有效(它很hacky),因为:
_controller
(eg is in different widget)._controller
在不同范围内的情况(例如,在不同的小部件中)。An easy way of doing this by listening TextEditingController
, while the TextFormField
is the ruler here.一个简单的方法是通过监听
TextEditingController
,而TextFormField
是这里的标尺。
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
late TextEditingController _controller;
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
_controller = TextEditingController()
..addListener(() {
Provider.of<AppState>(context, listen: false)
.updateSomeValue(_controller.text);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(context.watch<AppState>().someValue),
),
body: Center(
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _controller,
),
ElevatedButton(
onPressed: () {
_controller.text = 'foo_bar';
},
child: Text('change text external source'))
],
),
),
),
);
}
}
import 'package:flutter/foundation.dart';
class AppState extends ChangeNotifier
{
TextEditingController _controller=TextEditingController();
TextEditingController get controller=>_controller();
String someValue = '';
updateSomeValue(String newValue)
{
someValue = newValue;
notifyListeners();
}
}
main.dart主要.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:text_ctrl_issue/app_state.dart';
void main() {
runApp(ChangeNotifierProvider(create: (_) => AppState(), child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@override
void dispose() {
super.dispose();
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
final provider = Provider.of<AppState>(context);
return Scaffold(
appBar: AppBar(
title: Text(provider.someValue),
),
body: Center(
child: Form(
key: _formKey,
child: Column(children: [
TextFormField(
controller: Provider.controller,
onChanged: (v) {
provider.updateSomeValue(v);
},
),
ElevatedButton(
onPressed: () {
provider.updateSomeValue('foo_bar');
},
child: Text('change text external source'))
])),
),
);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.