【问题标题】:Android EditText listener for cursor position change用于光标位置更改的 Android EditText 侦听器
【发布时间】:2011-08-23 04:07:54
【问题描述】:

我有一个带有 EditText 的对话框。 EditText 在创建时已被填充。当用户将光标放在文本的某些部分上或附近时,会弹出一个 Toast。

我的问题是监听光标位置的变化。另一个post 提出了同样的问题,并且接受的解决方案是

您可以覆盖 onSelectionChanged (int selStart, int selEnd) 以获取有关选择更改的通知。如果光标被移动,这也会被调用(在这种情况下 selStart == selEnd)

onSelectionChanged (int selStart, int selEnd) 是 TextView 类的受保护方法。如何覆盖它?

【问题讨论】:

  • 我已经在我的项目中成功地做到了这一点,但刚刚发现在某些手机上 onSelectionChanged() 被调用,而在其他手机上它没有被调用。两者都 > Android 4.0 ....

标签: android android-edittext


【解决方案1】:

只需继承或扩展类 EditText 并将以下代码添加到新创建的类中:

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

不要忘记向子类添加构造函数。 :)

【讨论】:

  • 谢谢大师,辛苦了。如果有人感兴趣,我已将我所做的详细信息附加到我的原始问题中。
  • 当我把它放在我的代码中时,我得到一个android.view.InflateException: Binary XML file...知道我做错了什么吗?
  • 如果您不能使用子类(例如,在 SearchView 中监听光标更改位置,这是一个复杂的布局,其中嵌入了 EditText它)。
  • @TedHopp 请看一下这个答案:stackoverflow.com/a/36389070/170842
  • 对于遇到@KamranAhmed 问题的任何人:您是否实现了三个必需的构造函数?您的 xml 元素是否指向项目中的正确包?
【解决方案2】:

您实际上可以在不继承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);

【讨论】:

  • SpanWatcher 是否只通知其范围内的更改?为什么是 INCLUSIVE_EXCLUSIVE?
  • 不,它会通知所有更改。它是INCLUSIVE,因为当您清除EditText 时不应将其删除。
  • 请注意,如果您调用setText,观察者将会丢失。
  • 您可以通过在TextWatcherafterTextChanged 方法中重新添加它来避免这种情况。
  • 在不选择任何内容的情况下移动光标时不会触发(OnePlus 7,API 31)。
【解决方案3】:

我在不同版本的 Android 上调试了一个相关问题(请随时评论您的发现,我会将它们添加到列表中)。

调查结果总结:


4.1.6(三星设备)

onSelectionChanged() 仅在文本编辑时被调用。


4.0.6(HTC 设备)

4.0.4(由三星 Note 1 设备上的用户 Arch1tect 报告)

onSelectionChanged() 会在光标更改(点击、移动等)时调用,但不会在文本编辑时调用。


在上述部分更改未通知您的情况下(某些 Android 版本中的文本编辑),您将不得不使用 TextWatcher 来执行此操作,例如在 afterTextChanged() 方法中。

【讨论】:

  • 我发现了同样的问题:三星 4.04(注 1):onSelectionChanged() 会在光标更改(点击、移动等)时被调用,但不会在文本编辑时调用。
【解决方案4】:

如果有人仍在寻找不继承 EditText 的解决方案:

(代码在 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``
            }
        }
    })

【讨论】:

  • 哇,它完美无缺……但文档说“如果没有 * 启用可访问性,则此方法无效。”
  • @mifthi 您可以使用sendAccessibilityEventUnchecked,因为它不会检查是否启用了可访问性
  • 看起来它并不适用于任何地方。至少搭载 Android 8.1 的三星 SM-T580 不会收到此呼叫(尽管它适用于原生 Android 8.1)。
  • @ookami.kb 你用的是sendAccessibilityEventUnchecked 版本吗?
  • @SaeedEntezari 是的,两个都试过了。对于普通的 Android sendAccessibilityEvent 被调用,但对于三星 - 它们都没有。
【解决方案5】:

哦,天哪,非常感谢这个想法。绝对没有理由不将此功能放在 SDK 中。我有一个快速的子类,它实现了这个想法,但在选择发生变化时添加了侦听器的附加功能。希望有用。

public class EditTextSelectable extends EditText {

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

    private List<onSelectionChangedListener> listeners
        = new ArrayList<onSelectionChangedListener>();

    public void addOnSelectionChangedListener(OnSelectionChangedListener l) {
        listeners.add(l);
    }

    public void removeOnSelectionChangedListener(OnSelectionChangedListener l) {
        listeners.remove(l);
    }

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

}

【讨论】:

  • 嗨,你能帮我告诉我如何在活动中设置 OnSelectionChangedListener 吗?
  • @SWAppDev editText.addOnSelectionChangedListener(this) 不要忘记从 EditTextSelectable.onSelectionChangedListener 执行您的活动
【解决方案6】:

上述答案的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``                    
            }
        }
    });

【讨论】:

    【解决方案7】:

    这是Extension@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)
                }
            }
        })
    }
    

    【讨论】:

      【解决方案8】:

      提问者最初将他们的答案发布到问题中。我将其移至答案中以保持问题和答案分开。

      第一步:创建子类

      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.doAfterTextChanged {
            doSomething(editText.selectionStart , editText.selectionEnd)  
        }
        
        editText.setOnClickListener {
            doSomething(editText.selectionStart , editText.selectionEnd)  
        }
        

        【讨论】:

          猜你喜欢
          • 2011-04-08
          • 1970-01-01
          • 2018-09-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多