【问题标题】:Flutter: Update TextFormField text with ChangeNotifierFlutter:使用 ChangeNotifier 更新 TextFormField 文本
【发布时间】:2021-01-13 19:55:52
【问题描述】:

在一个复杂的场景中,当扩展ChangeNotifier 的模型发送notifyListeners() 时,我需要更新一些TextFormFields 的文本。 问题是要更改TextFormField 的文本,您必须使用设置器TextFormField.text,这意味着重建,因此您不能将其用于build 方法。但是要访问模型的Provider,您需要context,它位于build 方法中。

MWE(很明显按钮在实际项目中的另一个Widget中,还有更多TextFormFields)

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);
      })
    ]));
  }
}

【问题讨论】:

    标签: flutter dart provider changenotifier


    【解决方案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);
          })
        ]));
      }
    }
    

    【讨论】:

    • 很奇怪...可能是 Chrome 设备的问题(我没有使用 Android/iOs 模拟器,而是使用 Chrome 进行测试)
    猜你喜欢
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    • 2019-03-18
    • 2022-01-05
    • 1970-01-01
    • 2021-02-03
    • 2022-01-22
    相关资源
    最近更新 更多