繁体   English   中英

Flutter:使用 ChangeNotifier 更新 TextFormField 文本

[英]Flutter: Update TextFormField text with ChangeNotifier

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

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

你的第二个例子在我运行时没有任何错误:

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

演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM