Reputation: 170
I have a TextField
with its textDirection
set to rtl
(Right-to-Left). When I select the TextField
, I expect the cursor go to the end, as usual, but cursor goes to one position before the end.
TextField(
textDirection: TextDirection.rtl,
controller: widget.controller,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(8),
isDense: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2,
color: Theme.of(context).primaryColor,
),
borderRadius: BorderRadius.circular(8),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1.7,
color: Colors.grey.withOpacity(0.3),
),
borderRadius: BorderRadius.circular(8),
),
),
),
);
How can I make the cursor appear at the end instead?
UPDATE: I realized that specifying controller in the TextField
make the problem appear. but i need cotroller in this situation.
Upvotes: 16
Views: 6791
Reputation: 1
The accepted answer doesn't work directly for me, had to customize the affinity property to work
onTap: () {
if (widget.controller == null) return;
if (widget.controller!.selection ==
TextSelection.fromPosition(TextPosition(
offset: widget.controller!.text.length - 1,
affinity: widget.controller!.selection.affinity))) {
setState(() {
widget.controller!.selection = TextSelection.fromPosition(
TextPosition(offset: widget.controller!.text.length));
});
}
},
Upvotes: 0
Reputation: 685
if you don't want to use setState
you can override selection
method
class CustomTextEdittingController extends TextEditingController {
CustomTextEdittingController({super.text = ''});
bool _isSelectionWithinComposingRange(TextSelection selection) {
return selection.start >= value.composing.start && selection.end <= value.composing.end;
}
bool isRTL(String? text) {
if (text?.isEmpty ?? true) return false;
return Bidi.detectRtlDirectionality(text![text.length - 1]);
}
@override
set selection(TextSelection newSelection) {
if (!isSelectionWithinTextBounds(newSelection)) {
throw FlutterError('invalid text selection: $newSelection');
}
if (value.selection == TextSelection.fromPosition(TextPosition(offset: text.length - 1)) && isRTL(text)) {
newSelection = TextSelection.fromPosition(TextPosition(offset: text.length));
}
final TextRange newComposing =
newSelection.isCollapsed && _isSelectionWithinComposingRange(newSelection) ? value.composing : TextRange.empty;
value = value.copyWith(selection: newSelection, composing: newComposing);
}
}
Upvotes: 1
Reputation: 11
You can fix it by add this function on your textfield
onTap: () {
if (searchController.text[searchController.text.length - 1] != ' ') {
searchController.text = (searchController.text + ' ');
}
if (searchController.selection ==TextSelection.fromPosition(
TextPosition(offset:
searchController.text.length - 1))) {
setState(() {});
}
}
Upvotes: 1
Reputation: 518
I think this because of each arabic character is encoded as 2 to 4 bytes.
Any way this code can do the trick
TextField(
onTap: (){
if(controller.selection == TextSelection.fromPosition(TextPosition(offset: controller.text.length -1))){
setState(() {
controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length));
});
}
},
controller: controller,
...
);
Upvotes: 20
Reputation: 448
You can try this action to move the cursor to the end of the text. Then place this controller in the controller in TextField.:
late TextEditingController _textEditingController;
@override
void initState() {
_textEditingController = TextEditingController(text: widget.text);
_textEditingController.selection = TextSelection.fromPosition(
TextPosition(offset: _textEditingController.text.length));
super.initState();
}
Upvotes: 2
Reputation: 51
You can control cursor position by using TextSelection.
I didn't test Arabic environment, but try this.
offset value means position of cursor, so test 0 or (widget.controller.text.length)
TextField(
textDirection: TextDirection.rtl,
controller: widget.controller
..selection = TextSelection.fromPosition(TextPosition(offset: 0)),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(8),
isDense: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2,
color: Theme.of(context).primaryColor,
),
borderRadius: BorderRadius.circular(8),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1.7,
color: Colors.grey.withOpacity(0.3),
),
borderRadius: BorderRadius.circular(8),
),
),
),
);
Upvotes: 2