TextWatcher - курсор возвращается к началу EditText

У меня есть следующее определение TextWatcher:

   _textWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(final Editable s) {
            if (!s.toString().equals(_prev)) {
                afterTextHandler.removeCallbacks(work);
                work = new Runnable() {
                    @Override
                    public void run() {                            
                        if (!s.toString().equals(_prevQuoteAmount)) {
                            _prev = s.toString();
                            doSomething();
                        }
                        _et.append("");                            
                    }
                };
                afterTextHandler.postDelayed(work, 1000);
            }
            _et.append("");                
        }
    };

Все работает так, как ожидалось (иногда doSomething() выполняется, а иногда нет, поэтому его выполнение не имеет отношения к вопросу), но после того, как пользователь вводит некоторый текст в компоненте EditText, к которому прикреплен этот наблюдатель, курсор текста возвращается к началу EditText.

У меня есть следующий журнал, который отображается после выполнения onTextChanged() (или выполнения его обработчика run()):

12-08 13:10:55.777 1855-1855/com.android.inputmethod.latin I/LatinIME: запуск ввода. Позиция курсора = 4,4

Почему курсор EditText помещается в начало EditText сразу после выполнения onTextChanged()?

Редактировать 1: _et.append("") - это хак, который должен переместить курсор в последнее место текста. Это не работает здесь (хотя это работает в других случаях).

Редактировать 2: Запрошенные знания о doSomething:

    if (isReady()) {
        Sender objSender = new Sender();
        objSender.setParam1(_tvParam1.getText().toString());
        objSender.setParam2(_tvParam2.getText().toString());
        objSender.setParam3(_et.getText().toString());
        Service.startActionSend(getActivity(), quote);
    }

isReady() - проверяет условия (_tvParam1, _tvParam2, _et) перед выполнением сетевого запроса. Service.startActionSend() - выполнение асинхронного сетевого запроса (используя IntentService).

Редактировать 3: проблема возникает только при входе в метод run() обработчика.


person lionheart    schedule 08.12.2016    source источник


Ответы (4)


вы можете использовать эту функцию, чтобы курсор также использовался в setSelection текста редактирования

private fun getNewCursorPosition(digitCountToRightOfCursor : Int, numberString : String) : Int{
    var position = 0
    var c = digitCountToRightOfCursor
    for (i in numberString.reversed()) {
        if (c == 0)
            break

        if (i.isDigit())
            c --
        position ++


    }
    return numberString.length - position
}

для всего использования образца

editText.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(p0: Editable?) {
        }

        override fun beforeTextChanged(p0: CharSequence?, start: Int, count: Int, after: Int) {
            beforeText = p0.toString()
        }

        override fun onTextChanged(p0: CharSequence?, start: Int, before: Int, count: Int) {
            
            if (p0 == null)
                return
            // 1. get cursor position : p0 = start + before
            val initialCursorPosition = start + before
            //2. get digit count after cursor position : c0
            val numOfDigitsToRightOfCursor = getNumberOfDigits(beforeText.substring(initialCursorPosition,
                    beforeText.length))
            val newAmount = formatAmount(p0.toString())
            editText.removeTextChangedListener(this)
            editText.setText(newAmount)
            //set new cursor position
            editText.setSelection(getNewCursorPosition(numOfDigitsToRightOfCursor, newAmount))
            editText.addTextChangedListener(this)



        }

    })

также вам может понадобиться эта функция

 private fun getNumberOfDigits(@NonNull text : String) : Int{
    var count = 0
    for (i in text)
        if (i.isDigit())
            count++
    return count
}

Я не уверен, что вы делаете внутри doSomething(), но если это каким-то образом меняет положение курсора, вы можете использовать следующий (хак), чтобы довести курсор до конца ввода текст.

person Ahmed Abdallah    schedule 02.09.2020

mEdittext.setSelection(mEdittext.length());

Попробуйте логическую переменную, чтобы проверить статус

person Swayam    schedule 08.12.2016
comment
Могу я увидеть вашу функцию doSomething()? Мне интересно, что происходит внутри. - person lionheart; 08.12.2016
comment
Я отредактировал вопрос и добавил дополнительную информацию о doSomething(). Спасибо. - person Swayam; 08.12.2016
comment
Ссылка: ПОЛНОЕ описание кода - person lionheart; 08.12.2016

Для меня это разрешилось, когда я удалил textAllCaps, focusable и focusableInTouchMode.

desc.addTextChangedListener(new TextWatcher() {
        boolean changed = false;
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void afterTextChanged(Editable editable) {
            if (desc.getText().toString().isEmpty()) {

                changed = false;
            } else {
                if(!changed) {
                    doSomething();
                }
                changed = true;
            }
        }
    });
person Googlian    schedule 12.11.2018

 <EditText
    android:id="@+id/user_input_first_name"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:maxLines="1"
    android:textAllCaps="true"
    android:textColor="@color/black"
    android:textSize="20sp"
    android:textStyle="bold" />

Я отредактировал некоторую информацию о взломе, который я уже использую в примере кода вопроса. Я тоже попробовал твой, и он не работает. Кроме того, иногда doSomething() выполняется, а иногда нет, что означает, что это не влияет на результат.

person Raptor King    schedule 06.11.2020