如何在Flutter中更改文本框内的值?

170

我有一个 TextEditingController,如果用户点击按钮,它会填充信息。但我似乎无法弄清如何更改 TextfieldTextFormField 中的文本。是否有解决方法?

13个回答

275

只需更改text属性即可。

    TextField(
      controller: txt,
    ),
    RaisedButton(onPressed: () {
        txt.text = "My Stringt";
    }),

txt只是一个TextEditingController

  var txt = TextEditingController();

35
使用这段代码会使光标移动到字段的左侧,有没有办法修复它? - rickdroio
4
请看这个答案,它会把光标放在最后。链接为https://dev59.com/dVUK5IYBdhLWcg3w4jQv#57232719 - CopsOnRoad
@rickdroio 是的,下面有评论 https://dev59.com/dVUK5IYBdhLWcg3w4jQv#58307018 - Jose Jet
1
那我需要为每个想要数据绑定的输入框添加一个TextEditingController吗? - Josiel Faleiros
光标位置设置为-1,这是答案。 - user2233706

86

仅仅进行设置的问题

_controller.text = "New value";

这意味着光标将重新定位到开头(在材料的TextField中)。使用

_controller.text = "Hello";
_controller.selection = TextSelection.fromPosition(
    TextPosition(offset: _controller.text.length),
);
setState(() {});

由于它在设置文本属性和调用setState时重建widget的次数超过必要程度,因此它不够高效。

--

我认为最好的方法是将所有内容合并为一个简单的命令:

final _newValue = "New value";
_controller.value = TextEditingValue(
      text: _newValue,
      selection: TextSelection.fromPosition(
        TextPosition(offset: _newValue.length),
      ),
    );

它适用于Material和Cupertino文本字段,并可以正常工作。


4
这应该是正确的答案,因为它解决了控制器值的更改问题以及光标总是回到文本开头的问题。 - Jose Jet
10
还有一个建议,当提供偏移量时,我们可以这样做: int currentOffset = _textEditingController.selection.base.offset; 然后将currentOffset作为偏移量提供。这也可以处理用户处于字符串中间的情况。 - Abhinav

57

截图:

enter image description here

  1. 创建一个TextEditingController

final TextEditingController _controller = TextEditingController();
将其分配给您的 TextFieldTextFormField:
TextField(controller: _controller)
  • 若要使用光标位置上的按钮来更新文本(假设文本框中已经有文本):

  • ElevatedButton(
      onPressed: () {
        const newText = 'Hello World';
        final updatedText = _controller.text + newText;
        _controller.value = _controller.value.copyWith(
          text: updatedText,
          selection: TextSelection.collapsed(offset: updatedText.length),
        );
      },
    )
    

    30

    您可以使用文本编辑控制器来操作文本字段内的值。

    var textController = new TextEditingController();
    

    现在创建一个新的文本框,并将 textController 设置为文本框的控制器,如下所示。

     new TextField(controller: textController)
    

    现在,在您的代码中创建一个 RaisedButton,并将所需的文本设置在 RaisedButtononPressed 方法中。

    new RaisedButton(
           onPressed: () {
              textController.text = "New text";
           }
        ),
    

    11
    改变文本框的文本时不需要调用setState函数。 - Nihad Delic

    14
    _mytexteditingcontroller.value = new TextEditingController.fromValue(new TextEditingValue(text: "My String")).value;
    

    如果有更好的方法,请随时告诉我。看起来这个方法是可行的。


    3
    那么只需要这样:_mytexteditingcontroller.text = "你的文本" - Raouf Rahiche
    如果您想创建一个已经填充值的TextField,这将是完美的选择 :) - Touré Holder

    11

    第一件事

      TextEditingController MyController= new TextEditingController();
    

    然后将其添加到init State或任何SetState中

        MyController.value = TextEditingValue(text: "ANY TEXT");
    

    9
    如果您将_controller用作成员并使用StatefulWidget,则该问题不会出现。听起来很奇怪,但从无状态转换为有状态可以正常工作(这是因为小部件在每次输入到文本编辑控制器时都会重绘,而文本编辑控制器不会保留状态)。例如: 有状态的:(正常工作)
    class MyWidget extends StatefulWidget {
      const MyWidget(
          {Key? key})
          : super(key: key);
    
      @override
      _MyWidgetState createState() =>
          _MyWidgetState();
    }
    
    class _MyWidgetState
        extends State<MyWidget> {
      late TextEditingController _controller;
    
      @override
      void initState() {
        super.initState();
    
        _controller = TextEditingController(text: "My Text");
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            TextField(
              controller: _controller,
            ),
          ],
        );
      }
    }
    

    无状态:(问题)

    class MyWidget extends StatelessWidget {
      const MyWidget(
          {Key? key})
          : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            TextField(
              controller: TextEditingController(text: "My Text"),
            ),
          ],
        );
      }
    }
    

    1
    我喜欢无状态控制器的解决方案。太简单了。谢谢! - AndroidDev

    5

    如果您只想替换文本编辑控制器中的整个文本,则其他答案是有效的。但如果您想要以编程方式插入、替换选择或删除文本,则需要更多的代码。

    自定义键盘就是其中一种使用情况,下面所有的插入和删除操作都是通过程序完成的:

    enter image description here

    插入文本

    这里的_controller是用于TextFieldTextEditingController

    void _insertText(String myText) {
      final text = _controller.text;
      final textSelection = _controller.selection;
      final newText = text.replaceRange(
        textSelection.start,
        textSelection.end,
        myText,
      );
      final myTextLength = myText.length;
      _controller.text = newText;
      _controller.selection = textSelection.copyWith(
        baseOffset: textSelection.start + myTextLength,
        extentOffset: textSelection.start + myTextLength,
      );
    }
    

    感谢这个Stack Overflow答案帮助了我。

    删除文本

    需要考虑以下几种不同的情况:

    1. 有选定的文本(删除选定的部分)
    2. 光标在文本开头(不执行任何操作)
    3. 其他情况(删除前面的字符)

    这是实现代码:

    void _backspace() {
      final text = _controller.text;
      final textSelection = _controller.selection;
      final selectionLength = textSelection.end - textSelection.start;
    
      // There is a selection.
      if (selectionLength > 0) {
        final newText = text.replaceRange(
          textSelection.start,
          textSelection.end,
          '',
        );
        _controller.text = newText;
        _controller.selection = textSelection.copyWith(
          baseOffset: textSelection.start,
          extentOffset: textSelection.start,
        );
        return;
      }
    
      // The cursor is at the beginning.
      if (textSelection.start == 0) {
        return;
      }
    
      // Delete the previous character
      final newStart = textSelection.start - 1;
      final newEnd = textSelection.start;
      final newText = text.replaceRange(
        newStart,
        newEnd,
        '',
      );
      _controller.text = newText;
      _controller.selection = textSelection.copyWith(
        baseOffset: newStart,
        extentOffset: newStart,
      );
    }
    

    完整代码

    您可以在我的文章“Flutter中的自定义应用程序键盘”中找到完整的代码和更多说明。


    我正在使用这段代码,当textField的值不为空时,基本上是在开头添加值,但问题是当它添加$符号后,输入光标的位置会改变,并从值之前开始写入。例如,如果先前的值为$1,则它会写入2$1。所以是否有任何解决方案或更好的逻辑来完成此任务?"onChanged:(value){if(dollarSignAdded == false){priceTextEditingController.value = TextEditingValue(text:“\ $”+ priceTextEditingController.text); dollarSignAdded = true;} else if(value.isEmpty){dollarSignAdded = false;}}" - Arslan Kaleem

    1
    这是一个完整的示例,其中父组件控制子组件。父组件使用计数器更新子组件(TextTextField)。
    要更新 Text 组件,只需传入 String 参数即可。 要更新 TextField 组件,需要传入控制器,并在控制器中设置文本。

    main.dart:

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Demo',
          home: Home(),
        );
      }
    }
    
    class Home extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
              title: Text('Update Text and TextField demo'),
            ),
            body: ParentWidget());
      }
    }
    
    class ParentWidget extends StatefulWidget {
      @override
      _ParentWidgetState createState() => _ParentWidgetState();
    }
    
    class _ParentWidgetState extends State<ParentWidget> {
      int _counter = 0;
      String _text = 'no taps yet';
      var _controller = TextEditingController(text: 'initial value');
    
      void _handleTap() {
        setState(() {
          _counter = _counter + 1;
          _text = 'number of taps: ' + _counter.toString();
          _controller.text  = 'number of taps: ' + _counter.toString();
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(children: <Widget>[
            RaisedButton(
              onPressed: _handleTap,
              child: const Text('Tap me', style: TextStyle(fontSize: 20)),
            ),
            Text('$_text'),
            TextField(controller: _controller,),
          ]),
        );
      }
    }
    

    1
    1. 声明TextEditingController。

    2. 将控制器提供给TextField。

    3. 使用控制器的text属性来更改textField的值。

    请遵循官方问题解决方案


    2
    这个添加对之前添加的解决方案有什么贡献? - sjsam

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接