TextWatcher 用于多个 EditText

Posted

技术标签:

【中文标题】TextWatcher 用于多个 EditText【英文标题】:TextWatcher for more than one EditText 【发布时间】:2011-05-16 01:07:04 【问题描述】:

我想为多个EditText 字段实现TextWatcher 接口。目前我正在使用:

text1.addTextChangedListener(this);
text2.addTextChangedListener(this);

然后覆盖我的 Activity 中的方法:

public void afterTextChanged(Editable s) 

public void beforeTextChanged(CharSequence s, int start, int count, int after) 
public void onTextChanged(CharSequence s, int start, int before, int count) 

 // do some operation on text of text1 field
 // do some operation on text of text2 field 

然而这工作正常,但我正在寻找其他方法,以便我可以明确识别 SoftKeyboard 当前关注的 EditText 字段。

【问题讨论】:

How to use Single TextWatcher for multiple EditTexts?的可能重复 @SkyKelsey 您写的答案实际上是创建多个 TextWatcher 实例,因此我认为这不是 OP 提出的问题的完美答案,关于我的问题是关于在TextWatcher 接口方法。 github.com/henrychuangtw/AutoInsertEditText 【参考方案1】:

@Sebastian Roth's answer 中的建议解决方案对于某些EditTexts 而言不是TextWatcher 的一个实例。对于 n 个EditTexts,它是一个类和该类的 n 个实例。

每个 EditText 都有自己的 Spannable。 TextWatcher 的事件有这个 Spannable 作为 s 参数。我检查他们的 hashCode (每个对象的唯一 ID)。 myEditText1.getText() 返回 Spannable。所以如果myEditText1.getText().hashCode() 等于s.hashCode() 这意味着s 属于myEditText1

因此,如果您想为某些 EditTexts 提供一个 TextWatcher 实例,您应该使用这个:

private TextWatcher generalTextWatcher = new TextWatcher()     

    @Override
    public void onTextChanged(CharSequence s, int start, int before,
            int count) 

        if (myEditText1.getText().hashCode() == s.hashCode())
        
            myEditText1_onTextChanged(s, start, before, count);
        
        else if (myEditText2.getText().hashCode() == s.hashCode())
        
            myEditText2_onTextChanged(s, start, before, count);
        
    

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) 

        if (myEditText1.getText().hashCode() == s.hashCode())
        
            myEditText1_beforeTextChanged(s, start, count, after);
        
        else if (myEditText2.getText().hashCode() == s.hashCode())
        
            myEditText2_beforeTextChanged(s, start, count, after);
        
    

    @Override
    public void afterTextChanged(Editable s) 
        if (myEditText1.getText().hashCode() == s.hashCode())
        
            myEditText1_afterTextChanged(s);
        
        else if (myEditText2.getText().hashCode() == s.hashCode())
        
            myEditText2_afterTextChanged(s);
        
    

;

myEditText1.addTextChangedListener(generalTextWatcher);
myEditText2.addTextChangedListener(generalTextWatcher);

【讨论】:

您是否仔细检查了此解决方案?如果用户在两个输入字段中输入相同的文本会怎样? @SebastianRoth 每个 EditText 都有自己的 Spannable。 TextWatcher 事件将此 Spannable 作为 CharSequenceEditable 参数。我不检查 EditTexts 的文本值。我检查他们的 hashCode (每个对象的唯一 ID)。 myEditText1.getText() 返回 Spannable 而不是 Text 值。所以如果myEditText1.getText().hashCode()等于s.hashCode()意味着s属于myEditText1 好的,感谢您的编辑。但现在我有另一个问题。 (我对 android 和 Java 还很陌生,所以请多多包涵。)我不明白您为什么要使用 hashCode() 方法来测试可跨对象是否是相同的对象。为什么不将它们与“==”进行比较? (在 C# 中我会使用 ObjectEquals(),但在 Java 中只使用 ==,对吗?) 这是一个糟糕的解决方案。只要您有两个具有相同字符串的 EditText,它将失败,因为它将是内存中的相同字符串(因此相同的哈希码)。 您确定所有哈希值都是唯一的吗?哈希冲突呢?【参考方案2】:

我会这样做:

@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    EditText e = new EditText(this);
    e.addTextChangedListener(new CustomTextWatcher(e));


private class CustomTextWatcher implements TextWatcher 
    private EditText mEditText;

    public CustomTextWatcher(EditText e)  
        mEditText = e;
    

    public void beforeTextChanged(CharSequence s, int start, int count, int after) 
    

    public void onTextChanged(CharSequence s, int start, int before, int count) 
    

    public void afterTextChanged(Editable s) 
    

【讨论】:

有趣的想法,但这意味着每个 EditText 都有一个单独的文本观察器。 这个答案不是Single TextWatcher for multiple EditTexts。它是一个 TextWatcher 类的 3 个实例。所以 3 个独立的 TextWatchers 控制着 3 个 EditTexts。 @breceivemail,一个类,3 个实例。同意当人们不指定他们的对象类型时很难。他的目标是只编写一次代码,所以它就是这样。 这有什么好习惯的?没看懂 @Bobs,我想制作 3 个对象比编写一个对象更容易,并支持它未来的变化。【参考方案3】:

我使用这个解决方案:

添加返回监听器的方法:

private TextWatcher getTextWatcher(final EditText editText) 
    return new TextWatcher() 
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) 

        

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) 
            // do what you want with your EditText
            editText.setText("blabla");
        

        @Override
        public void afterTextChanged(Editable editable) 

        
    ;

为多个EditText添加监听器,也可以传递其他参数:

editText1.addTextChangedListener(getTextWatcher(editText1));
editText2.addTextChangedListener(getTextWatcher(editText2));
editText3.addTextChangedListener(getTextWatcher(editText3));

【讨论】:

有史以来最好的答案......代码没有什么可改变的。非常感谢你 简单,因此是“最佳答案” 工作就像一个魅力。【参考方案4】:

使用“CustomTextWatcher”的想法,我做到了

1) 创建了一个新的 TextWatcherListener 接口:

public interface TextWatcherExtendedListener extends NoCopySpan

    public void afterTextChanged(View v, Editable s);

    public void onTextChanged(View v, CharSequence s, int start, int before, int count);

    public void beforeTextChanged(View v, CharSequence s, int start, int count, int after);

2)创建和使用 EditTextExtended 而不是 EditText(在我的情况下):

public class EditTextExtended extends EditText

   private TextWatcherExtendedListener  mListeners = null;

   public EditTextExtended(Context context) 
   
     super(context);
   

   public EditTextExtended(Context context, AttributeSet attrs)
   
      super(context, attrs);
   

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

   public void addTextChangedListener(TextWatcherExtendedListener watcher) 
       
       if (mListeners == null) 
       
           mListeners = watcher;
       
   

   public void removeTextChangedListener(TextWatcherExtendedListener watcher) 
   
       if (mListeners != null) 
       
           mListeners = null;        
       
   

   void  sendBeforeTextChanged(CharSequence text, int start, int before, int after)
   
       if (mListeners != null) 
       
           mListeners.beforeTextChanged(this, text, start, before, after);
       
   

   void  sendOnTextChanged(CharSequence text, int start, int before,int after) 
   
       if (mListeners != null) 
       
           mListeners.onTextChanged(this, text, start, before, after);
       
   

   void  sendAfterTextChanged(Editable text) 
   
       if (mListeners != null)
       
           mListeners.afterTextChanged(this, text);
       
   

3) 那么,你需要在哪里写下这段代码:

myEditTextExtended.addTextChangedListener(this) //Let implement TextWatcherExtendedListener methods

4) 使用它们:

@Override
public void onTextChanged(View v, CharSequence s, int start, int before, int count) 

   //Tested and works
   //do your stuff  



@Override
public void beforeTextChanged(View v, CharSequence s, int start, int count, int after)
   
     //not yet tested but it should work    


@Override
public void afterTextChanged(View v, Editable s) 

    //not yet tested but it should work 

好吧,让我知道你的想法。

【讨论】:

我认为这是解决这个问题的最直接的方法。 +1【参考方案5】:

--编辑--

如果您只想使用 afterTextChanged 比较可编辑项:

@Override
public void afterTextChanged(Editable editable) 
    if (editable == mEditText1.getEditableText()) 
        // DO STH
     else if (editable == mEditText2.getEditableText()) 
        // DO STH
    

【讨论】:

这不是假设在多个 EditText 视图中永远不会有相同的文本吗?取决于可能不是有效假设的应用程序。 该死,我很抱歉,但我现在确信我错了。我现在认为您的原始版本和编辑版本都是正确的 - 您正在将 EditText.getEditableText() 返回的 Java 对象与提供的可编辑实现对象进行比较,而不是所涉及的文本。 (在我的测试中,这两个对象似乎总是一个 SpannableStringBuilder 对象,Google 的 SpannableStringBuilder.equals() 文档清楚地表明它比较的是对象,而不是包含的文本。) @RenniePet 我的答案的第一个版本是错误的。我们不应该比较编辑文本的值。现在效果很好。我看到我的答案应该在这个帖子的顶部。 由于某种原因,这在我的模拟器中有效,但在真实设备中无效,最后,这个答案对我有用:***.com/a/13787221/2263329比较EditablehashCode()【参考方案6】:

另一种方法是将OnClickListener 添加到EditText 并设置一个全局变量,如下所示

EditText etCurrentEditor;//Global variable

@Override
    public void onClick(View v) 
        // TODO Auto-generated method stub
        if(v instanceof EditText)
            etCurrentEditor=(EditText)v;
        
    

将此 etCurrentEditor 用作对当前编辑的 EditText 的引用

@Override
    public void afterTextChanged(Editable editable) 
        // TODO Auto-generated method stub
        switch (etCurrentEditor.getId()) 
        case R.id.EDITTEXTID:
            break;
        default:
            break;
        
    

【讨论】:

【参考方案7】:

我将其实现为:

edittext1.addTextChangedListener(this);
edittext2.addTextChangedListener(this);
edittext3.addTextChangedListener(this);

和:

@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) 



@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) 
    if(edittext1.hasFocus())
        //text changed for edittext1
    else if(edittext2.hasFocus())
        //text changed for edittext2
    else 
        //text changed for edittext3
    


@Override
public void afterTextChanged(Editable editable) 


【讨论】:

【参考方案8】:

在尝试了几种方法来实现这一点后,我找到了使用EditText.isFocused() 区分彼此的正确方法。例如:

    private class OnTextChangedListener implements TextWatcher 

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) 

    

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) 

    

    @Override
    public void afterTextChanged(Editable editable) 
        if (edtName.isFocused()) 
            //do something
         else if (edtEmail.isFocused()) 
            //do something
         else if (edtContent.isFocused()) 
             //do something
        
    

【讨论】:

【参考方案9】:

是的,您可以使用存储TextView 的自定义TextWatcher 的多个实例。 (TextView 实际上是具有addTextChangedListener 的类。)

类似于上面的 hashCode 解决方案,您只需检查 getText()==s。 无需存储所有控件或多次存储findViewById,您只需自己扫描一次内容树以查找具有CharSequence 的控件。

public TextView findTextView(View v, CharSequence s)

   TextView tv;
   ViewGroup vg;
   int i, n;

   if (v instanceof TextView)
   
      tv = (TextView) v;
      if (tv.getText()==s) return(tv);
   

   else if (v instanceof ViewGroup)
   
      vg = (ViewGroup) v;
      n = vg.getChildCount();
      for(i=0;i<n;i++)
      
         tv = findTextView(vg.getChildAt(i), s);
         if (tv!=null) return(tv);
      
   

   return(null);


public void afterTextChanged(Editable s)

   TextView tv=findTextView(findViewById(android.R.id.content), s);
   if (tv==null) return;
   switch(tv.getId())
   
      case R.id.path:
         break;
      case  R.id.title:
         break;
   

当然你也可以在beforeTextChangedonTextChanged中使用findTextView

【讨论】:

绝妙的解决方案。在 TextWatcher 覆盖的方法中使用时,它可以识别我正在编辑的 EditText。你能解释一下你是如何得到这个解决方案并使用`findViewById(android.R.id.content) 来获取编辑视图的吗? findViewById(android.R.id.content) 有点矫枉过正,它为您提供了保存您内容的ViewGroup。最好选择最低的ViewGroup,它包含所有感兴趣的文本更改内容。【参考方案10】:

所有活动的全球一堂课。

CustomTextWatcher.java

package org.logicbridge.freshclub.customizedItems;

import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
    public class CustomTextWatcher implements TextWatcher 
        private EditText mEditText;
        Context context;

        public CustomTextWatcher(EditText e, Context context) 
            mEditText = e;
            this.context = context;
        

        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) 
        

        public void onTextChanged(CharSequence s, int start, int before, int count) 
        

        public void afterTextChanged(Editable s) 

        
    

【讨论】:

【参考方案11】:

您可以这样做以获取编辑文本的 ID。它未经测试,但如果它有效,请告诉我。

//setting textWatcher for the editText
textWatcher(owner_name);


public void textWatcher(final EditText editText)

    TextWatcher watcher = new TextWatcher() 
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) 

           if(editText.getId()==R.id.your_id)
             //Do something
              
        

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) 
          if(editText.getId()==R.id.your_id)
          //Do something
          
        

        @Override
        public void afterTextChanged(Editable s)  
    ;

    editText.addTextChangedListener(watcher);

【讨论】:

【参考方案12】:

您始终可以将TextWatcher 定义为addTextChangedListener 方法的参数。这样您可以为每个编辑文本有多个定义。

【讨论】:

【参考方案13】:

只需使用 hashCode() 方法比较编辑文本和字符串的哈希码

@Override
public void afterTextChanged(Editable s) 

    if (editext.getText().hashCode() == s.hashCode())
        type1Total(type1List);
    


【讨论】:

【参考方案14】:

这就是我所做的……

private TextWatcher textWatcher = new TextWatcher() 
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) 

    

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) 

        if (editText1.getText().length() > 0
                && editText2.getText().length() > 0
                && editText3.getText().length() > 0) 

            button.setEnabled(true);
         else 

            button.setEnabled(false);
        

    

    @Override
    public void afterTextChanged(Editable s) 

    

然后只需在 onCreate 方法中将 TextWatcher 添加到每个 EditText 并在此处默认保留按钮 setEnabled(false)。

button.setEnabled(false); 

    editText1.addTextChangedListener(textWatcher);
    editText2.addTextChangedListener(textWatcher);
    editText3.addTextChangedListener(textWatcher);

【讨论】:

【参考方案15】:

如果您使用的是 Kotlin,扩展功能就可以完成这项工作。 比如我们需要给editText1editText2添加TextWatcher

像这样创建一个扩展函数,

 fun EditText.addTextWatcher() 
        this.addTextChangedListener(
                object : TextWatcher 
                    override fun afterTextChanged(s: Editable?) 

                    

                    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) 

                    

                    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) 
                        // you do some common operations here

                        when (this@addTextWatcher) 
                            editText1 -> 
                                // do something for editText1
                            
                            editText2 -> 
                                // do something for editText2
                            
                        
                    
                
        )
    

然后像这样将 textwatcher 添加到 EditTexts

editText1.addTextWatcher()
editText2.addTextWatcher()

【讨论】:

【参考方案16】:

我已经做了这样的事情,只有一个TextWatcher 类可以控制来自ActivityFragment 的尽可能多的EditText

您需要先创建一个MultiTextWatcher 类,如下所示

class MultiTextWatcher 

    private var callback: TextWatcherWithInstance? = null

    fun setCallback(callback: TextWatcherWithInstance): MultiTextWatcher 
        this.callback = callback
        return this
    


    fun registerEditText(editText: EditText): MultiTextWatcher 
        editText.addTextChangedListener(object : TextWatcher 
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) 
                callback!!.beforeTextChanged(editText, s, start, count, after)
            

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) 
                callback!!.onTextChanged(editText, s, start, before, count)
            

            override fun afterTextChanged(editable: Editable) 
                callback!!.afterTextChanged(editText, editable)
            
        )

        return this
    

     interface TextWatcherWithInstance 
        fun beforeTextChanged(editText: EditText, s: CharSequence, start: Int, count: Int, after: Int)

        fun onTextChanged(editText: EditText, s: CharSequence, start: Int, before: Int, count: Int)

        fun afterTextChanged(editText: EditText, editable: Editable)
    

然后在您的ActivityFragment 中,您需要注册尽可能多的EditText,如下所示,而且我使用Data Binding 来获取XML 视图的引用,您可以用你的方式。

 private fun setTextWatchers() 
        MultiTextWatcher()
            .registerEditText(binding.etCompanyAddress)
            .registerEditText(binding.etCompanyIntro)
            .registerEditText(binding.etCompanyName)
            .registerEditText(binding.etCompanyPhone)
            .setCallback(object : MultiTextWatcher.TextWatcherWithInstance 
                override fun beforeTextChanged(editText: EditText, s: CharSequence, start: Int, count: Int, after: Int) 
                

                override fun onTextChanged(editText: EditText, s: CharSequence, start: Int, before: Int, count: Int) 
                    when (editText) 
                        binding.etCompanyAddress -> 
                            //do your logic here
                        
                        binding.etCompanyPhone -> 
                            //do your logic here and so on
                        
                    
                

                override fun afterTextChanged(editText: EditText, editable: Editable) 

                
            )
    

【讨论】:

以上是关于TextWatcher 用于多个 EditText的主要内容,如果未能解决你的问题,请参考以下文章

android TextWatcher 更改外部类私有字段

Edittext textwatcher触发listview中的所有editexts

带有TextWatcher和LiveData的EditText中的光标位置?

当TextWatcher存在时退格/删除时按EditText光标位置

如何使用 TextWatcher Android 将 3 位小数货币格式添加到edittext

Android开发中给EditText控件添加TextWatcher监听实现对输入字数的限制