Skip to content

When EditText has emoji, the maximum length of editable.dart will be abnormal length and cursor abnormality #55670

@Linsixu

Description

@Linsixu

/***
*** my class example : maxlength = 15
***/

TextField(
                 controller: TextEditingController.fromValue(TextEditingValue(
                                  text: _txtController.text,
                                  selection: TextSelection.fromPosition(
                                      TextPosition(affinity: TextAffinity.downstream, offset:_txtController.text.length)))),
                 decoration: InputDecoration(
                           border: InputBorder.none,
                  ),
                 style: TextStyle(fontSize: 16),
                  inputFormatters: [
                                LengthLimitingTextInputFormatter(15),
                   ]
)

descrition: When the input box contains an emoticon, when 16 characters are input, the input box can still display the 16th character, and then the cursor moves to the 15th character position.

my hope:When the input box contains an emoticon, when 16 characters are input, the input box can still display 15 characters, and then the cursor moves to the 15th character position.

find:I find the source -(editable_text.dart) do not deal with max length state.
So I want to solve this bug only through the business layer to make logical judgments。

My Solution for suspension

  1. add field to get maxLength number;
  2. This is what I need for work;(this is my work need)
     final int selfMaxLength;
     final Function maxLengthCallBack;
     final TextEditingController myController;

    @override 
    void initState() {
    ……
    myController =  TextEditingController.fromValue(TextEditingValue(
                                  text: _txtController.text,
                                  selection: TextSelection.fromPosition(
                                      TextPosition(affinity: TextAffinity.downstream, offset:_txtController.text.length))));
    if (widget.controller.text.length == widget.selfMaxLength) {
       hasAlreadyMaxLength = true;
       lastMaxContent = widget.controller.text;
    } else {
      hasAlreadyMaxLength = false;
      lastMaxContent = "";
          }
    }
 
    @override
    Widget build(BuildContext context) {
          return Container(
                child: TextField(
                 controller: myController,
                 decoration: InputDecoration(
                           border: InputBorder.none,
                  ),
                 style: TextStyle(fontSize: 16),
                  inputFormatters: [
                                LengthLimitingTextInputFormatter(15),
                   ],
                   onChanged: (String value) {
                    _actionMaxLengthState(value);
                  }
                 )
          )
    }

    void _resetSelection(String newText) {
     var sRunes = newText.runes;
     String result;
     for (int i = 0; i < sRunes.length; i++) {
         if (String.fromCharCodes(sRunes, 0, sRunes.length - i).length <= widget.selfMaxLength) {
         result = String.fromCharCodes(sRunes, 0, sRunes.length - i);
         break;
      }
    }
    TextSelection temp = myController.value.selection.copyWith(
      baseOffset: result.length,
      extentOffset: result.length,
    );
    TextRange fixRange = widget.controller.value.composing;
    if (widget.controller.value.composing.end > result.length) {
      fixRange = TextRange(start: fixRange.start, end: result.length);
    } 
    
    //composing is used iOS inputMethod
    myController.value = TextEditingValue(text: result, selection: temp, composing: fixRange);
    lastMaxContent = result;
    }

    void _initOldDataSelection(String newText) {
          TextSelection actualSelection = myController.value.selection;
          actualSelection = myController.value.selection.copyWith(
                  baseOffset: lastMaxContent.length,
                  extentOffset: lastMaxContent.length,
           );
    //ios: When TextRange is not -1, the next update will replace all the variable values ​​of start and end directly. When you are sure that the content is unchanged, please change them to -1
    TextRange fixRange = TextRange(start: -1, end: -1);
          myController.value = TextEditingValue(text: lastMaxContent, selection: actualSelection, composing: fixRange);
    }

    void _actionMaxLengthState(String newText) {
    if (newText.length >= widget.selfMaxLength) {
      if (maxLengthCallBack != null) maxLengthCallBack();
      if (hasAlreadyMaxLength) {
        _initOldDataSelection(newText);
      } else {
        hasAlreadyMaxLength = true;
        _resetSelection(newText);
      }
    } else {
      //For the controller's text setting, you must change the value or set the text directly, and the selection is the default value of -1.
      widget.controller.value = TextEditingValue(text: newText, selection: widget.controller.value.selection, composing: widget.controller.value.composing);
      hasAlreadyMaxLength = false;
      lastMaxContent = "";
      }
    }

Finally, I hope flutter Team can resovle this question.

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: text inputEntering text in a text field or keyboard related problemsf: material designflutter/packages/flutter/material repository.frameworkflutter/packages/flutter repository. See also f: labels.waiting for PR to land (fixed)A fix is in flight

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions