我正在制作一个笔记应用程序并使用 Provider 管理应用程序的状态。当用户选择一个
Note
对象(从存储在Provider中的List<Note>
)时,所选注释的title
和content
字段将显示在两个TextField
小部件中。一个小部件存储 selectedNote.title
,另一个存储 selectedNote.content
。每个TextField
都有一个TextEditingController
当用户更改
TextField
的值时,我想在我的 Provider 中调用更新方法。
我遇到的问题是调用
update
会触发小部件重建。重建 TextField
小部件时,TextEditingController
重新分配其文本,并且光标移动到文本字段的末尾。
我尝试使用
context.read<Data>().update()
,认为 context.read<T>()
可以避免小部件重建 - 但这并没有发生。
我还尝试将
TextField
放在单独的小部件中,认为它们的父级可能会在子级不重建的情况下重建 - 但这并没有发生。
作为参考,这里是关键代码片段(
Note
是一个简单的数据模型类,带有 String title
、String content
字段):
来自提供商
class Data extends ChangeNotifier {
List<Note> notes = [];
Note selectedNote = Note('', '');
void update({title = '', content = ''}) {
// Don't do anything if user hasn't selected a note
if (selectedNote.title != '' || selectedNote.content != '') {
if (title != '') selectedNote.title = title;
if (content != '') selectedNote.content = content;
notifyListeners();
writeJson(); //<--separate method; not important to my question
}
}
从显示小部件
class _NoteDetailState extends State<NoteDetail> {
final TextEditingController noteTitleController = TextEditingController();
final TextEditingController noteContentController = TextEditingController();
@override
void dispose() {
noteContentController.dispose();
noteTitleController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
Note? selectedNote = context.read<Data>().selectedNote;
return DefaultTabController(
// ...code...
body: TabBarView(
children: [
Container(
margin: const EdgeInsets.all(18),
child: ListView(
children: [
// Note's Title TextField---------------------------------
NoteTextField(
displayText: selectedNote.title,
controller: noteTitleController,
onChanged: (value) {
context.read<Data>().update(title: value);
},
minLines: 1,
style: Theme.of(context).textTheme.titleLarge!,
),
// Note's Content TextField---------------------------------
NoteTextField(
displayText: selectedNote.content,
controller: noteContentController,
onChanged: (value) {
context.read<Data>().update(content: value);
},
minLines: 10,
),
// ...more code...
NoteTextField 的小部件:
class NoteTextField extends StatelessWidget {
const NoteTextField(
{super.key,
required this.displayText,
required this.controller,
required this.onChanged,
required this.minLines,
this.style});
final String displayText;
final TextEditingController controller;
final Function(String) onChanged;
final int minLines;
final TextStyle? style;
@override
Widget build(BuildContext context) {
controller.text = displayText;
return Padding(
padding: EdgeInsets.only(
top: 15,
bottom: 15,
),
child: TextField(
controller: controller,
style: style,
keyboardType: TextInputType.multiline,
maxLines: null,
onChanged: onChanged,
),
);
}
}
附注我确实需要调用
notifyListeners()
来更新应用程序中其他地方的值。
这不会停止重建,而是会将光标移动到行尾。
controller;
..text = displayText
..selection = TextSelection(
baseOffset: displayText.length,
extentOffset: displayText.length,
);