krishnakumarcn
krishnakumarcn

Reputation: 4199

Flutter: How to insert text in middle of text field text

I have a text field in flutter and an emoji picker button. On selecting an emoji I need to insert it at the current cursor position. How can I achieve this? Currently using TextEditingController I'm only able to append the emoji. I'm not able to get the current cursor offset.

emojiPicker() {
    return EmojiPicker(
      rows: 3,
      columns: 7,
      recommendKeywords: null,
      indicatorColor: flujoAccentColor,
      onEmojiSelected: (emoji, category) {
        print(emoji);
        _messageInputController.text =
            _messageInputController.text + emoji.emoji;
     }
    );
  }

Upvotes: 10

Views: 9239

Answers (5)

Csaba Mihaly
Csaba Mihaly

Reputation: 329

TextSelection selection = _controller.selection;
String text = _controller.text;
//textInside to get the selected text if you want to do something with is                
String selectedText = selection.textInside(text);
_controller.text ='${text.substring(0, selection.start)}$insert${text.substring(selection.end, text.length)}';
             

Upvotes: 0

Jenkins Gage
Jenkins Gage

Reputation: 1

If you want to replace the selection of text field with a new string, I found the method below is useful.

void replaceTextSelectionWith(TextEditingController textEditingController, Function(String selection) getReplaceString)
{
  final text = textEditingController.text;
  final selection = textEditingController.selection;
  final replaceText = getReplaceString(selection.textInside(text)) as String;
  final newText = text.replaceRange(selection.start, selection.end, replaceText);

  textEditingController.value =
      TextEditingValue(text: newText, selection: TextSelection.collapsed(offset: selection.start + replaceText.length));
}

And use it like this

replaceTextSelectionWith(textEditingController, (selection) => '**$selection**');

Upvotes: 0

Suragch
Suragch

Reputation: 512326

This is a slight modification to CrazyLazyCat's answer.

void _insertText(String inserted) {
  final text = _controller.text;
  final selection = _controller.selection;
  final newText = text.replaceRange(selection.start, selection.end, inserted);
  _controller.value = TextEditingValue(
    text: newText,
    selection: TextSelection.collapsed(offset: selection.baseOffset + inserted.length),
  );
}

Notes:

  • _controller is a TextEditingController.
  • If you are changing both the text and the selection then you should use a TextEditingValue rather than changing them individually (since they each trigger an update).
  • Generally if you insert something you want the cursor to appear after then insert, thus the TextSelection.collapsed with the adjusted index.

Upvotes: 9

Sayyid J
Sayyid J

Reputation: 1573

i have another solution beside text.replaceRange.

All you need is :

TextEditingController _tec;

String youWillAddtoTEC = "your emoji or your clipboard data or else";

String beforeCursorPositionAtTEC = tec.selection.textBefore(tec.text);

String afterCursorPositionAtTEC = tec.selection.textAfter(tec.text);

String result = beforeCursorPositionAtTEC + youWillAddtoTEC + afterCursorPositionAtTEC;

and then add result to tec, or any widget your need:

tec.text = result;

for the selection or cursor position is same with above, but if you need place cursor after the "youWillAddToTEC" you can do like this:

tec.selection = TextSelection.collapsed(offset: tec.selection.start + youWillAddtoTEC.lenght);

Upvotes: 1

Crazy Lazy Cat
Crazy Lazy Cat

Reputation: 15073

  1. Use _txtController.selection to get the selection (or cursor position).
  2. replace the selection with selected emoji.
  3. then fix the selection(or cursor position) of the controller
import 'package:emoji_picker/emoji_picker.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: HomePage()));
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  TextEditingController _messageInputController;

  @override
  void initState() {
    _messageInputController = TextEditingController();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Demo"),
      ),
      body: SafeArea(
        child: Column(
          children: <Widget>[
            EmojiPicker(
              rows: 3,
              columns: 7,
              recommendKeywords: null,
              indicatorColor: Colors.red,
              onEmojiSelected: (emoji, category) {
                String text = _messageInputController.text;
                TextSelection textSelection = _messageInputController.selection;
                String newText = text.replaceRange(
                    textSelection.start, textSelection.end, emoji.emoji);
                final emojiLength = emoji.emoji.length;
                _messageInputController.text = newText;
                _messageInputController.selection = textSelection.copyWith(
                  baseOffset: textSelection.start + emojiLength,
                  extentOffset: textSelection.start + emojiLength,
                );
              },
            ),
            TextField(
              controller: _messageInputController,
            ),
          ],
        ),
      ),
    );
  }
}

with this you can not only insert the selected emoji at cursor position, but also can replace some selected text

Upvotes: 23

Related Questions