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

how to set cursor position at the end of the value in flutter in textfield?

我想在文本字段值的末尾添加 ,00

它在 iOS 设备中运行良好,但在 android 中光标移动到文本字段中值的起点。因此,我无法添加 ,00.

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

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

似乎有效的解决方案如下:

  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 文本字段中光标未更新问题的唯一方法。

我用这个

解决了我的问题

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

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

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

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

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

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

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

Creates a collapsed selection at the given text position. A collapsed selection starts and ends at the same offset, which means it contains zero characters but instead serves as an insertion point in the text.

查看了TextEditingControllertextsetter的注释,里面说[text]和[selection]不能同时改,但是对于 phone 输入,我们希望为输入应用某种格式(例如“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,
  );

}

以下代码非常适合我。

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

如果您想在文本中间的某处添加特殊字符(在您的情况下为 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))
);

这对我有用:

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

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

创建一个新的 Dart class,扩展 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
    );
  }
}

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

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

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

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

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

下面的代码对 Dart >= 2.12 具有空安全性,并使用最新的 TextSelection API

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

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

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

)

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

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

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

TextField(
    scrollController: scrollController,
    controller: textFieldController
)

现在跳转到TextField的末尾:

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

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

  1. TextEditingControllerScrollController 添加到 TextField

记得init/dispose他们在initStatedispose

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

我也遇到了类似的问题,试图将 TextEditingController.text 中的文本更改为与 onChanged 中的 NumberFormat("###,###,###.##") 匹配的格式化字符串,同时尝试保留当前光标位置并结束做这样的事情:

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

一个简单的例子会帮助你。

 if (int.parse(mintues) > 59) mintuesController.text = '59';
                mintuesController.selection = TextSelection.fromPosition(
                    TextPosition(offset: mintues.length));