简体   繁体   English

当状态改变时如何使用 Provider/ChangeNotifier 使 TextFormField 颤动?

[英]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:我将我的问题简化为抽象问题(我删除了所有杂乱的代码)以及它是如何工作的:

  • there is a someValue in AppState AppState中有一个someValue
  • the someValue can be edited via Form->TextFormField someValue可以通过Form->TextFormField进行编辑
  • the someValue is to be reflected as a title of the AppBar when typing ( onChange ) someValue将在键入时反映为 AppBar 的标题( onChange
  • the someValue can be updated from external source (in the example it is a button that updates it) someValue可以从外部源更新(在示例中它是一个更新它的按钮)
  • when 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),因为:

  1. it listens to every event (eg onFocus or cursor changed)它监听每个事件(例如 onFocus 或光标改变)
  2. it does not take into account situation that EleveatedButton is in different scope than _controller (eg is in different widget).它没有考虑 EleveatedButton 与_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'))
            ],
          ),
        ),
      ),
    );
  }
}

Also, you can check riverpod此外,您可以检查riverpod

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.

相关问题 Flutter:在上下文不可用时使用 changeNotifier 和提供程序 - Flutter : using changeNotifier and provider when the context is not available 如何在 flutter 中与提供程序一起使用 changeNotifier - How to use changeNotifier in flutter with provider 如何使用 Flutter 中的 Provider 显示来自 ChangeNotifier 的错误 - How to show errors from ChangeNotifier using Provider in Flutter Flutter:使用 ChangeNotifier 更新 TextFormField 文本 - Flutter: Update TextFormField text with ChangeNotifier 如何关闭 ChangeNotifier Provider Flutter 中的函数 - How to close Functions in ChangeNotifier Provider Flutter 如何使用提供程序将ChangeNotifier的作用域限定为某些路由? - How to scope a ChangeNotifier to some routes using Provider? 无法在 Changenotifier class 中创建 getter。 在 Flutter 中使用 Provider 时出错 - Unable to create getter in Changenotifier class. error when using Provider in Flutter Flutter - 使用 Provider + ChangeNotifier 更改主题颜色(primarySwatch) - Flutter - Changing theme color (primarySwatch) using Provider + ChangeNotifier 如何对 ChangeNotifier Provider state 的值进行单元测试? - How to unit test the value from a ChangeNotifier Provider state? 如何在提供者 ChangeNotifier flutter 中设置和获取对象值 - how to set and get object value in provider ChangeNotifier flutter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM