Android EditText listener for cursor position chan

2019-01-11 02:54发布

问题:

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?

Solution that worked for me ... Hi Guru, thankyou for your reply, it worked. Here is what I did in detail if anyone else is interested...

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

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

}