Прослушиватель 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)
}