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 作为 CharSequence
或 Editable
参数。我不检查 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比较Editable
的hashCode()
。【参考方案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;
当然你也可以在beforeTextChanged
和onTextChanged
中使用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,扩展功能就可以完成这项工作。
比如我们需要给editText1
和editText2
添加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
类可以控制来自Activity
或Fragment
的尽可能多的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)
然后在您的Activity
或Fragment
中,您需要注册尽可能多的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的主要内容,如果未能解决你的问题,请参考以下文章
Edittext textwatcher触发listview中的所有editexts
带有TextWatcher和LiveData的EditText中的光标位置?
当TextWatcher存在时退格/删除时按EditText光标位置