【问题标题】:TextWatcher for more than one EditTextTextWatcher 用于多个 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 字段。

【问题讨论】:

标签: android interface android-activity android-edittext textwatcher


【解决方案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 我的答案的第一个版本是错误的。我们不应该比较编辑文本的值。现在效果很好。我看到我的答案应该在这个帖子的顶部。
  • 由于某种原因,这在我的模拟器中有效,但在真实设备中无效,最后,这个答案对我有用:stackoverflow.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) {
                    
                                    }
                                })
                        }
                    

                    【讨论】:

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