如何使用 Provider 存储对 TextEditingController 文本的更改,而不导致小部件重新加载其文本?

问题描述 投票:0回答:1

我正在制作一个笔记应用程序并使用 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()
来更新应用程序中其他地方的值。

flutter textfield flutter-provider texteditingcontroller
1个回答
0
投票

这不会停止重建,而是会将光标移动到行尾。

 controller;
      ..text = displayText
      ..selection = TextSelection(
        baseOffset: displayText.length,
        extentOffset: displayText.length,
      );
© www.soinside.com 2019 - 2024. All rights reserved.