【问题标题】:how to set cursor position at the end of the value in flutter in textfield?如何在文本字段中颤动的值末尾设置光标位置?
【发布时间】:2019-11-13 01:21:23
【问题描述】:

问题是我想在文本字段值的末尾添加“,00”在 iOS 设备中效果很好,但在 android 中光标移动到文本字段中值的起点。所以,我无法添加“,00”。

【问题讨论】:

  • 请贴一些代码sn-p,到目前为止你已经尝试过什么。

标签: flutter


【解决方案1】:

我在设置 TextEditingController 时遇到了同样的问题,这对我有用。

controller.text = someString;
controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length));

TextSelection.fromPosition() 执行以下操作(来自文档):

在给定的文本位置创建一个折叠的选择。一个倒塌的 选择以相同的偏移量开始和结束,这意味着它包含 零个字符,而是用作文本中的插入点。

【讨论】:

  • 你救了我!!非常感谢。我实际上只需要使用 Material Textfield 来执行此操作,CupertinoTextfield 的行为与预期相同.. 将操纵文本分配给其 TextEditingController 光标始终位于末尾。因为我认为这应该是文本字段的默认行为,所以我向 Flutter 团队提交了一个问题,因为如果你有类似这样的不同行为,这会扼杀 Flutter 的目的。它并不是真正的多平台。我敢肯定这是由于不同的团队..但是,嘿,应该就事情达成一致..无论如何..再次感谢优雅的解决方法。
  • 嗨。在我升级到 Catalina 后,Android Studio 4.0 Flutter 最新的开发频道,您的解决方案中的代码不再有效。您是否知道任何使此解决方案无效的更改?在这里你可以找到我在我的应用程序stackoverflow.com/questions/62244027/… 中使用的代码。我实际上发现这个解决方案只需要在网络上......在设备上(只在 iPad 上测试)新文本刚刚添加到最后......正如预期的那样。
  • 我忘了.. 这是我放在 GitHub 上的示例应用程序,用于向颤振团队 github.com/vinnytwice/material_textfield_issue_test 展示问题;)干杯。
  • ok.. 在 iPad 上检查过,升级到 Catalina/Android Studio 4.0、Xcode 11.5 后,iOS 上也需要您的代码.. 好吧.. 至少现在所有平台都对齐了.. 哈哈跨度>
  • 当键盘有字典、自动更正和/或建议时,这不起作用
【解决方案2】:

我用这个解决了我的问题

这会将您的光标设置在文本字段的末尾。

您可以随时随地调用代码,当它被调用时,它会设置光标位置。

或者简单地将这段代码放在文本字段的onChanged()方法中

final val = TextSelection.collapsed(offset: _textTEC.text.length); 
 _textTEC.selection = val;

【讨论】:

    【解决方案3】:

    这对我有用:

    _inputCtrl.value = TextEditingValue(
      text: suggestion,
      selection: TextSelection.collapsed(offset: suggestion.length),
    );
    

    https://github.com/flutter/flutter/issues/11416#issuecomment-507040665

    【讨论】:

    • 只有这个解决方案对我有用。其他的有时间问题,因为使用editingController.text = 'something'设置文本;花了几毫秒,因此随后的 editor.selection = TextSelection.fromPosition(...);不会有任何影响。
    • 这是唯一对我有用的解决方案。我想以前的答案存在同步问题,同时给出文本和选择就像这样很有魅力。
    【解决方案4】:

    这对我来说就像一个魅力。

    myController.text = newText;
    myController.selection = TextSelection(
        baseOffset: newText.length,
        extentOffset: newText.length)
    

    【讨论】:

      【解决方案5】:

      查看TextEditingControllertextsetter的注释,上面说[文本]和[选择]不应该同时改变,但是对于电话输入,我们'想为输入应用某种格式(例如'131 1111 1111'),同时保持光标始终在末尾。

      所以我只用了一个自定义的TextEditingController,就可以了!

      class PhoneEditingController extends TextEditingController {
      
        @override
        set text(String newText) {
          value = value.copyWith(
          text: newText,
          selection: TextSelection.collapsed(offset: newText.length),
          composing: TextRange.empty,
        );
      
      }
      

      【讨论】:

      • 也许他们已经更新了?我认为它鼓励同时更新而不是单独更新 ?/// 这个属性可以从添加到这个 [TextEditingController] 的监听​​器中设置;但是,也应该在单独的语句中设置[selection]。要同时更改 [text] 和 [selection],请更改控制器的 [value]。
      • 朋友,如果堆栈溢出让我给你两个赞。就我而言,使用电话输入格式化程序(即在写作时添加连字符、括号等的格式化程序)是您的答案。谢谢。
      【解决方案6】:

      似乎可行的解决方案如下:

      1. 为文本字段的构造函数提供一个 TextEditingController 参数:

        var myTextEditingController = TextEditingController();
        var myTextField = TextField(..., controller: myTextEditingController);
        
      2. 在文本字段中设置新文本时,请像这样使用 TextEditingController:

        myTextEditingController.value.copyWith(
          text: newText,
          selection: TextSelection(
            baseOffset: newText.length,
            extentOffset: newText.length
          )
        )
        

      这似乎非常复杂,但它似乎是解决 Flutter 文本字段中光标未更新问题的唯一解决方案。

      【讨论】:

      • 为什么需要copyWith
      【解决方案7】:

      您可以使用 .. 运算符如果您在控制器中设置值如下:

      final _controller = TextEditingController()..text = txtValue
            ..selection = TextSelection.collapsed(offset: txtValue.length);
      
      )
      

      我认为它在设置值运行时非常有用。

      【讨论】:

      • 谢谢。这似乎是最清晰和最干净的方式。
      • 在运行时设置值很有用
      【解决方案8】:

      以下代码非常适合我。

      _controller.value = _controller.value.copyWith(
        text: newText,
        selection: TextSelection.fromPosition(
          TextPosition(offset: newText.length),
        ),
      );
      

      【讨论】:

        【解决方案9】:

        如果您想在文本中间的某处添加特殊字符(在您的情况下为 00),则使用 _textController.text.length 作为光标的基本偏移量不起作用。在这种情况下,以下解决方案应该有效:

        String specialChars = '00';
        int length = specialChars.length;
        // current cursor position, where you want to add your special characters
        int cursorPos = _textController.selection.base.offset;
        // the text before the point you want to add the special characters
        String prefixText = _textController.text.substring(0, cursorPos);
        // the text after the point ...
        String suffixText = _textController.text.substring(cursorPos);
        
        _textController.text = prefixText + specialChars + suffixText;
        // set the cursor position right after the special characters
        _textController.selection = TextSelection(baseOffset: cursorPos + length, extentOffset: cursorPos + length);
        

        或者你也可以这样做,都是一样的:

        int cursorPos = _textController.selection.base.offset;
        _textController.value = _textController.value.copyWith(
          text: _textController.text.replaceRange(cursorPos, cursorPos, '00'),
          selection: TextSelection.fromPosition(TextPosition(offset: cursorPos + 2))
        );
        

        【讨论】:

          【解决方案10】:

          创建一个新的 Dart 类,扩展 TextEditingController,您可以使用自定义的 TextController 来代替:

          class TextController extends TextEditingController {
          
            TextController({String text}) {
              this.text = text;
            }
          
            set text(String newText) {
              value = value.copyWith(
                text: newText,
                selection: TextSelection.collapsed(offset: newText.length),
                composing: TextRange.empty
              );
            }
          }
          

          【讨论】:

            【解决方案11】:

            我有一个TextField,并且我有一个定期向其附加文本的方法。我想水平滚动到该文本字段的最右端以查看最后附加的字符串,或者我想将光标移动到最后附加的字符。

            对我有用的唯一技巧是使用scrollController,并在每次附加文本时调用jump() 方法:

            TextField(
                scrollController: scrollController,
                controller: textFieldController
            )
            

            现在跳转到TextField的末尾:

            scrollController.jumpTo( scrollController.position.pixels+500);
            

            【讨论】:

              【解决方案12】:

              如果您的新值太长。您应该将视图滚动到新的光标位置。

              1. TextEditingControllerScrollController 添加到TextField

              记得在initStatedispose中初始化/处置它们

              TextField(
              controller: controller,
              scrollController: scrollController,
              )
              
              1. TextEditingController 设置新值和光标位置
              controller.text = newValue;
              controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length));
              
              1. 将视图滚动到该位置
              Future.delayed(Duration(milliseconds: 50),(){
               scrollController.jumpTo(scrollCtrl.position.maxScrollExtent);
              });
              
              

              【讨论】:

                【解决方案13】:

                您需要一个FocusNode 并设置TextSelection 来放置光标。

                这里的代码可能是一个开始:Position cursor at end of TextField when focused?

                【讨论】:

                • 我试过这个,但正如你的建议中提到的那样,它不起作用。
                【解决方案14】:

                根据documentation,将文本和位置设置在一起的可能方法是使用value...像这样:

                _controller.value = _controller.value.copyWith(text: newText, selection: newSelection)
                

                【讨论】:

                  【解决方案15】:

                  有很多解决方案,但在下面的代码中,我合并了来自 Github 和 SO 的最佳答案。

                  下面的 Dart >= 2.12 具有 null-safety 并使用最新的 TextSelection APIs

                  import 'package:flutter/widgets.dart';
                  
                  class TextEditingControllerWithEndCursor extends TextEditingController {
                  
                    TextEditingControllerWithCursorPosition({
                      String? text
                    }): super(text: text);
                  
                    @override
                    set text(String newText) {
                      value = value.copyWith(
                        text: newText,
                        selection: TextSelection(
                          baseOffset: newText.length,
                          extentOffset: newText.length
                        ),
                        composing: TextRange.empty,
                      );
                    }
                  }
                  

                  【讨论】:

                    【解决方案16】:

                    我也遇到了类似的问题,试图将TextEditingController.text 中的文本更改为匹配NumberFormat("###,###,###.##") 内部onChanged 的格式化字符串,同时尝试保留当前光标位置并最终执行以下操作:

                    TextFormField(
                      controller: controller,
                    
                      onChanged: (value) {
                        final formatter = NumberFormat("###,###,###.##");
                        final amount = formatter.parse(value);
                    
                        //allow user to enter any letter at the end without clearing it.
                        //otherwise if the user enters "." it would get truncated by
                        //the formatter
                        if (amount == 0 || value.startsWith(formatter.format(amount.floor()))) {
                          return;
                        }
                    
                        final editor = controller.value;
                    
                        //only do something if the IME is not in the middle of composing
                        if (editor.composing.isCollapsed) {
                          //offset is the position of the cursor
                          int offset = editor.selection.extentOffset;
                    
                          final pretty = formatter.format(amount);
                    
                          if(offset >= value.length) {
                            //set the offset to the length of the new string
                            offset = pretty.length;
                    
                          } else {
                            //count how many chars are in the string to the left
                            //of the cursor position, excluding formatting chars [,.-]
                    
                            final partial = value.substring(0, offset);
                            for (var unit in partial.codeUnits) {
                              if (unit >= 44 && unit <= 46) offset--;
                            }
                    
                            //traverse the formatted string by the same number of
                            //characters skipping over the formatting chars [,.-].
                            int i = 0;
                            for (var unit in pretty.codeUnits) {
                              if (i++ >= offset) break;
                              if (unit >= 44 && unit <= 46) offset++;
                            }
                            //offset is now where the new cursor position should be
                          }
                    
                          //finally update the controller to the new offset
                          controller.value = editor.copyWith(
                            text: pretty,
                            selection: TextSelection.collapsed(offset: offset),
                            composing: TextRange.collapsed(offset),
                          );
                        }
                      },
                    )
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2011-05-31
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-04-26
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-03-19
                      相关资源
                      最近更新 更多