Amir Mohammad HP
Amir Mohammad HP

Reputation: 170

Flutter TextField: Cursor position goes to one before the last when selecting a RTL TextField

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.

this is the result

 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

Answers (6)

Ahmed Tarek
Ahmed Tarek

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

Mohsen Haydari
Mohsen Haydari

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

Hosam Jameel Ghrayeb
Hosam Jameel Ghrayeb

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

Omar Alkattan
Omar Alkattan

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

Sulaymon Ne&#39;matov
Sulaymon Ne&#39;matov

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

kkimoooooo
kkimoooooo

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

Related Questions