如何在文本字段中颤动的值末尾设置光标位置?

Posted

技术标签:

【中文标题】如何在文本字段中颤动的值末尾设置光标位置?【英文标题】: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,到目前为止你已经尝试过什么。 【参考方案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 最新的开发频道,您的解决方案中的代码不再有效。您是否知道任何使此解决方案无效的更改?在这里你可以找到我在我的应用程序***.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】:

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

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

    var myTextEditingController = TextEditingController();
    var myTextField = TextField(..., controller: myTextEditingController);
    

    在文本字段中设置新文本时,请像这样使用 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】:

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

    TextEditingControllerScrollController 添加到TextField

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

TextField(
controller: controller,
scrollController: scrollController,
)
    TextEditingController 设置新值和光标位置
controller.text = newValue;
controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length));
    将视图滚动到该位置
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),
      );
    
  ,
)

【讨论】:

以上是关于如何在文本字段中颤动的值末尾设置光标位置?的主要内容,如果未能解决你的问题,请参考以下文章

将插入符号/光标位置设置为字符串值 WPF 文本框的末尾

如何在文本区域的末尾设置光标?

如何将光标设置到 Internet Explorer 中文本 INPUT 字段的字符串值中的特定位置?

FabricJS 文本框 - 某些字体的光标位置设置不正确

UITextField 将光标设置为开始文本位置

如何在颤动的按下/手指/鼠标/光标位置显示菜单