Прослушиватель Android EditText для изменения положения курсора

У меня есть диалог с EditText в нем. EditText уже заполняется при его создании. Когда пользователь помещает курсор на определенные части текста или рядом с ними, появляется всплывающее окно.

Моя проблема заключается в прослушивании изменений в позиции курсора. Другой пост задает тот же вопрос, и принятое решение было

Вы можете переопределить onSelectionChanged (int selStart, int selEnd), чтобы получать уведомления об изменениях выбора. Если курсор перемещается, это также вызывается (в данном случае selStart == selEnd)

onSelectionChanged (int selStart, int selEnd) является защищенным методом класса TextView. Как переопределить это?

Решение, которое сработало для меня... Привет Гуру, спасибо за ваш ответ, это сработало. Вот что я сделал подробно, если кому-то еще интересно...

Шаг первый: создайте подкласс

package com.example;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.EditText;
import android.widget.Toast;

public class EditTextCursorWatcher extends EditText {

    public EditTextCursorWatcher(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);

    }

    public EditTextCursorWatcher(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    public EditTextCursorWatcher(Context context) {
        super(context);

    }


     @Override   
     protected void onSelectionChanged(int selStart, int selEnd) { 
        Toast.makeText(getContext(), "selStart is " + selStart + "selEnd is " + selEnd, Toast.LENGTH_LONG).show();
         } 
}

Шаг второй: обратитесь к классу в файле макета (например, main.xml (хотя у меня был пользовательский макет диалога)). Не забудьте использовать полное имя пакета (в данном случае com.example.EditTextCursorWatcher, например

    <com.example.EditTextCursorWatcher
     android:id="@+id/etEdit"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="top"
    android:minLines="5"
    android:inputType="textMultiLine"/> 

9 ответов

Решение

Просто создайте подкласс или расширите класс EditText и добавьте следующий код во вновь создаваемый класс:

 @Override 
 protected void onSelectionChanged(int selStart, int selEnd) {
        // Do ur task here.
    }

Не забудьте добавить конструкторы в подкласс.:)

На самом деле вы можете прослушивать изменения выбора без подкласса EditText, Это немного сложнее, но все же управляемо. Для этого нужно добавить SpanWatcher к тексту и обрабатывать изменения диапазонов выбора.

final SpanWatcher watcher = new SpanWatcher() {
  @Override
  public void onSpanAdded(final Spannable text, final Object what,
      final int start, final int end) {
    // Nothing here.
  }

  @Override
  public void onSpanRemoved(final Spannable text, final Object what, 
      final int start, final int end) {
    // Nothing here.
  }

  @Override
  public void onSpanChanged(final Spannable text, final Object what, 
      final int ostart, final int oend, final int nstart, final int nend) {
    if (what == Selection.SELECTION_START) {
      // Selection start changed from ostart to nstart. 
    } else if (what == Selection.SELECTION_END) {
      // Selection end changed from ostart to nstart. 
    }
  }
};

editText.getText().setSpan(watcher, 0, 0, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

Если кто-то все еще ищет решение, которое не подкласс EditText:

(Код в котлине)

    editText.setAccessibilityDelegate(object : View.AccessibilityDelegate() {
        override fun sendAccessibilityEvent(host: View?, eventType: Int) {
            super.sendAccessibilityEvent(host, eventType)
            if (eventType == AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED){
                // here you can access selection of the editText 
                // with `editText.selectionStart`
                // and `editText.selectionEnd``
            }
        }
    })

Я отлаживал связанную проблему в разных версиях Android (не стесняйтесь комментировать ваши выводы, и я добавлю их в список).

Резюме выводов:


4.1.6 (устройство Samsung)

onSelectionChanged() вызывается только в текстовом редакторе.


4.0.6 (устройство HTC)

4.0.4 (сообщается пользователем Arch1tect на устройстве Samsung Note 1)

onSelectionChanged() вызывается при изменении курсора (щелчки, движения и т. д.), но НЕ при редактировании текста.


В вышеупомянутых случаях, когда вы не проинформированы об изменениях раздела (редактирование текста в некоторых версиях Android), вам придется сделать это, используя TextWatcherнапример, в afterTextChanged() метод.

О боже, большое спасибо за эту идею. Нет абсолютно никаких причин, почему эта функция не должна быть в SDK. У меня есть быстрый подкласс, который реализует эту идею, но добавляет дополнительную функцию слушателей, когда выбор изменяется. Надеюсь, это полезно

public class EditTextSelectable extends EditText {

    public interface onSelectionChangedListener {
         public void onSelectionChanged(int selStart, int selEnd);
}


private List<onSelectionChangedListener> listeners;

public EditTextSelectable(Context context) {
    super(context);
    listeners = new ArrayList<onSelectionChangedListener>();
}

public EditTextSelectable(Context context, AttributeSet attrs){
    super(context, attrs);
    listeners = new ArrayList<onSelectionChangedListener>();
}
public EditTextSelectable(Context context, AttributeSet attrs, int defStyle){
    super(context, attrs, defStyle);
    listeners = new ArrayList<onSelectionChangedListener>();
}

public void addOnSelectionChangedListener(onSelectionChangedListener o){
    listeners.add(o);
}

protected void onSelectionChanged(int selStart, int selEnd){
    for (onSelectionChangedListener l : listeners)
         l.onSelectionChanged(selStart, selEnd);        

}

Java-версия ответа выше,

mEtEditor.setAccessibilityDelegate(new View.AccessibilityDelegate(){
        /**
         * Sends an accessibility event of the given type. If accessibility is not
         * enabled this method has no effect.
         * <p>
         * The default implementation behaves as {@link View#sendAccessibilityEvent(int)
         * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate
         * been set.
         * </p>
         *
         * @param host      The View hosting the delegate.
         * @param eventType The type of the event to send.
         * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int)
         */
        @Override
        public void sendAccessibilityEvent(View host, int eventType) {
            super.sendAccessibilityEvent(host, eventType);
            if (eventType == AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED){
                // here you can access selection of the editText
                // with `editText.selectionStart`
                // and `editText.selectionEnd``                    
            }
        }
    });

Вот Extension версия того, что @Saeed Entezari опубликовал:

fun EditText.setSelectionChangedListener(onSelectionChangedListener: (editText: EditText, selectionStart: Int, selectionEnd: Int) -> Unit) {
    setAccessibilityDelegate(object : View.AccessibilityDelegate() {
        override fun sendAccessibilityEvent(host: View?, eventType: Int) {
            super.sendAccessibilityEvent(host, eventType)
            if (eventType == AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED){
                val editText = this@setSelectionChangedListener
                onSelectionChangedListener.invoke(editText, editText.selectionStart, editText.selectionEnd)
            }
        }
    })
}

Автор вопроса изначально разместил свой ответ в вопросе. Я перехожу в ответ, чтобы разделить вопрос и ответ.

Шаг 1. Создайте подкласс

package com.example;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.EditText;
import android.widget.Toast;

public class EditTextCursorWatcher extends EditText {

    public EditTextCursorWatcher(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);

    }

    public EditTextCursorWatcher(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    public EditTextCursorWatcher(Context context) {
        super(context);

    }


     @Override   
     protected void onSelectionChanged(int selStart, int selEnd) { 
        Toast.makeText(getContext(), "selStart is " + selStart + "selEnd is " + selEnd, Toast.LENGTH_LONG).show();
         } 
}

Шаг второй: обратитесь к классу в файле макета (например, main.xml (хотя у меня был настраиваемый макет диалогового окна)). Не забудьте использовать полное имя пакета (в данном случае com.example.EditTextCursorWatcher, например

    <com.example.EditTextCursorWatcher
     android:id="@+id/etEdit"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="top"
    android:minLines="5"
    android:inputType="textMultiLine"/> 
      editText.doAfterTextChanged {
    doSomething(editText.selectionStart , editText.selectionEnd)  
}

editText.setOnClickListener {
    doSomething(editText.selectionStart , editText.selectionEnd)  
}
Другие вопросы по тегам