how to set cursor position at the end of the value in flutter in textfield?
FlutterText CursorFlutter Problem Overview
I want to add ,00
at the end of the value of the textfield.
It works well in iOS device, but in android cursor moves to starting point of the value in textfield. As a result, I'm unable to add ,00
.
Flutter Solutions
Solution 1 - Flutter
I've been having the same problem with setting a TextEditingController
and this is what worked for me.
controller.text = someString;
controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length));
TextSelection.fromPosition()
does the following (from the documentation):
> 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.
Solution 2 - Flutter
I solved my issue by using this
this will set your cursor at the end in the textfield.
you can call the code from wherever and whenever it will set the cursor location when it is called.
or simple place this code in onChanged()
method of textfield
final val = TextSelection.collapsed(offset: _textTEC.text.length);
_textTEC.selection = val;
Solution 3 - Flutter
This worked for me:
_inputCtrl.value = TextEditingValue(
text: suggestion,
selection: TextSelection.collapsed(offset: suggestion.length),
);
https://github.com/flutter/flutter/issues/11416#issuecomment-507040665
Solution 4 - Flutter
This works for me like a charm.
myController.text = newText;
myController.selection = TextSelection(
baseOffset: newText.length,
extentOffset: newText.length)
Solution 5 - Flutter
You can use .. operator If you are setting value in the controller as below:
final _controller = TextEditingController()..text = txtValue
..selection = TextSelection.collapsed(offset: txtValue.length);
)
I think it's very useful when you are setting value runtime.
Solution 6 - Flutter
Checked the notes of the setter
of TextEditingController
's text
, it says the [text] and the [selection] shouldn't be changed at the same time, however for the phone inputting, we'd like to apply some format for the input (e.g. '131 1111 1111') while keeping the cursor always at the end .
So I just use a customized TextEditingController
, it works!
class PhoneEditingController extends TextEditingController {
@override
set text(String newText) {
value = value.copyWith(
text: newText,
selection: TextSelection.collapsed(offset: newText.length),
composing: TextRange.empty,
);
}
Solution 7 - Flutter
The solution that seems to work is the following:
-
Give a TextEditingController argument to the constructor of your text field:
var myTextEditingController = TextEditingController(); var myTextField = TextField(..., controller: myTextEditingController);
-
When setting the new text inside your text field, use the TextEditingController like that:
myTextEditingController.value.copyWith( text: newText, selection: TextSelection( baseOffset: newText.length, extentOffset: newText.length ) )
This seems extraordinary complicated for what it achieves but it seems to be the only solution to the problem of the cursor not being updated in Flutter text fields.
Solution 8 - Flutter
In case your new value is too long. You should scroll the view to the new cursor position.
- Add
TextEditingController
andScrollController
toTextField
.
Remember to init/dispose them in initState
and dispose
TextField(
controller: controller,
scrollController: scrollController,
)
- Set a new value and cursor position for the
TextEditingController
controller.text = newValue;
controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length));
- Scroll the view to the position
Future.delayed(Duration(milliseconds: 50),(){
scrollController.jumpTo(scrollCtrl.position.maxScrollExtent);
});
Solution 9 - Flutter
the following code worked perfectly for me.
_controller.value = _controller.value.copyWith(
text: newText,
selection: TextSelection.fromPosition(
TextPosition(offset: newText.length),
),
);
Solution 10 - Flutter
Using _textController.text.length
as the cursor's base offset doesn't work if you want to add your special characters (in your case 00
) somewhere in the middle of the text. In such cases, the following solution should work:
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);
or you can do it like this, it's the same thing:
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))
);
Solution 11 - Flutter
Create a new Dart class, extending TextEditingController and you can use your custom TextController instead that behaves:
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
);
}
}
Solution 12 - Flutter
I have a TextField
, and I have a method that appends text to it periodically. I wanted to scroll horizontally to the rightmost end of that text field to see the last appended string, or I want to move the cursor to the last character appended.
The only trick that worked for me was to use a scrollController
, and call the jump()
method every time I append text:
TextField(
scrollController: scrollController,
controller: textFieldController
)
Now jump to the end of the TextField
:
scrollController.jumpTo( scrollController.position.pixels+500);
Solution 13 - Flutter
You need a FocusNode
and set TextSelection
to place the cursor.
The code here may be a start: https://stackoverflow.com/questions/55019550/position-cursor-at-end-of-textfield-when-focused
Solution 14 - Flutter
According to the documentation the possible way to set the text and position together is using value
... like this:
_controller.value = _controller.value.copyWith(text: newText, selection: newSelection)
Solution 15 - Flutter
There are a lot of solutions but in the code below I've merged the best answers from Github and SO.
This below has null-safety for Dart >= 2.12 and uses latest 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,
);
}
}
Solution 16 - Flutter
I also had a similar problem trying to change the text in the TextEditingController.text
into a formatted string matching NumberFormat("###,###,###.##")
inside onChanged
while trying to preserve the current cursor location and ended up doing something like this:
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),
);
}
},
)
Solution 17 - Flutter
A simple example will help you.
if (int.parse(mintues) > 59) mintuesController.text = '59';
mintuesController.selection = TextSelection.fromPosition(
TextPosition(offset: mintues.length));