Android EditText listener for cursor position change

巧了我就是萌 提交于 2019-12-17 10:40:47

问题


I have a dialog with EditText in it. The EditText is already populated when it is created. When the user places the cursor on or near certain parts of the text a Toast will pop up.

My problem is listening for changes in cursor position. Another post asks the same question and the accepted solution was

You can override onSelectionChanged (int selStart, int selEnd) to get notified about selection changes. If the cursor is moved, this is called as well (in this case selStart == selEnd)

onSelectionChanged (int selStart, int selEnd) is a protected method of the TextView class. How do override it?


回答1:


Just subclass or extend the class EditText and add the following code to the newly create class:

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

Don't forget to add constructors to the subclass. :)




回答2:


You can actually listen to selection changes without subclassing an EditText. It's a little more complicated but still manageable. To do it you need to add a SpanWatcher to a text and handle changes of selection spans.

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);



回答3:


I debugged a related problem across different versions of Android (feel free to comment on your findings and I'll add them to the list).

Summary of findings:


4.1.6 (Samsung device)

onSelectionChanged() gets called on TEXT EDITS only.


4.0.6 (HTC Device)

4.0.4 (reported by user Arch1tect on Samsung Note 1 device)

onSelectionChanged() gets called on cursor changes (clicks, moves etc) but NOT on Text Edits.


In the cases above where you are not informed of the section changes (text edits in some versions of Android), you will have to do that using a TextWatcher, for example in the afterTextChanged() method.




回答4:


Oh goodness, thanks so much for this idea. There's absolutely no reason why this feature shouldn't be in the SDK. I have an quick subclass that implements this idea but adding on the additional feature of listeners for when the selection changes. Hope it's useful

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);        

}



回答5:


if anyone is still looking for a solution that does not Subclass the EditText:

(Code is in kotlin)

    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``
            }
        }
    })



回答6:


The java version of the above answer,

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``                    
            }
        }
    });



回答7:


The Question asker originally posted their answer into the question. I'm moving it into an answer to keep the question and answer separated.

Step One: Create the sub class

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();
         } 
}

Step Two: refer to the class in the layout file (eg main.xml (though mine was a custom dialog layout)). Don't forget to use full package name (in this case com.example.EditTextCursorWatcher, eg

    <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"/> 



回答8:


Here is an Extension version of what @Saeed Entezari posted:

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)
            }
        }
    })
}


来源:https://stackoverflow.com/questions/5962366/android-edittext-listener-for-cursor-position-change

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!