web-dev-qa-db-ja.com

addTextChangedListenerで追加されたすべてのリスナーを削除する方法

ListViewがあり、各行にはEditTextコントロールがあります。 TextChangedListenerを各行に追加します。 EditTextがどの行にあったかを示す追加データを含むもの。問題は、getViewが呼び出されると、複数のTextWatchersが追加されることです。 convertViewにはすでにTextWatcher(および別の行を指すもの)が含まれているためです。

MyTextWatcher watcher = new MyTextWatcher(currentQuestion);
EditText text = (EditText)convertView.findViewById(R.id.responseText);
text.addTextChangedListener(watcher);

MyTextWatcherTextWatcherを実装する私のクラスです。テキストイベントを処理します。 CurrentQuestionは、私が演じている行を知らせてくれます。ボックスに入力すると、 TextWatcherの複数のインスタンスが呼び出されます。

新しいものを追加する前にTextWatchersを削除する方法はありますか? removeTextChangedListenerメソッドが表示されますが、それには特定のTextWatcherを渡す必要があり、既に存在するTextWatcherへのポインターを取得する方法がわかりません。

49
GendoIkari

現在のEditTextインターフェイスを直接使用してこれを行う方法はありません。次の2つの解決策があります。

  1. 特定のTextWatcherインスタンスに追加されるEditTextが常にわかるように、アプリケーションを再設計します。
  2. EditTextを拡張し、すべてのウォッチャーをクリアする可能性を追加します。

次に、2番目のアプローチの例を示します-ExtendedEditText

public class ExtendedEditText extends EditText
{   
    private ArrayList<TextWatcher> mListeners = null;

    public ExtendedEditText(Context ctx)
    {
        super(ctx);
    }

    public ExtendedEditText(Context ctx, AttributeSet attrs)
    {
        super(ctx, attrs);
    }

    public ExtendedEditText(Context ctx, AttributeSet attrs, int defStyle)
    {       
        super(ctx, attrs, defStyle);
    }

    @Override
    public void addTextChangedListener(TextWatcher watcher)
    {       
        if (mListeners == null) 
        {
            mListeners = new ArrayList<TextWatcher>();
        }
        mListeners.add(watcher);

        super.addTextChangedListener(watcher);
    }

    @Override
    public void removeTextChangedListener(TextWatcher watcher)
    {       
        if (mListeners != null) 
        {
            int i = mListeners.indexOf(watcher);
            if (i >= 0) 
            {
                mListeners.remove(i);
            }
        }

        super.removeTextChangedListener(watcher);
    }

    public void clearTextChangedListeners()
    {
        if(mListeners != null)
        {
            for(TextWatcher watcher : mListeners)
            {
                super.removeTextChangedListener(watcher);
            }

            mListeners.clear();
            mListeners = null;
        }
    }
}

そして、これがxmlレイアウトでExtendedEditTextを使用する方法です:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:orientation="vertical" 
    Android:layout_width="fill_parent"
    Android:layout_height="fill_parent">

    <ua.inazaruk.HelloWorld.ExtendedEditText 
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content" 
        Android:text="header"
        Android:gravity="center" /> 

</LinearLayout>
39
inazaruk

EditTextからTextWatcherを削除できます。まず、TextWatcher宣言をeditText.addTextChangedListener(...)の外側に移動することをお勧めします。

protected TextWatcher yourTextWatcher = new TextWatcher() {

    @Override
    public void afterTextChanged(Editable s) {
        // your logic here
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // your logic here
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
       // your logic here
    }
};

その後、TextWatherをもう少し簡単に設定できるようになります。

editText.addTextChangedListener(yourTextWatcher);

次のようにTextWatcherを削除できます:

editText.removeTextChangedListener(yourTextWatcher);

必要に応じて別のものを設定します。

24

また、解決策を見つけるのに多くの時間を費やし、最終的に以下のようなタグの助けを借りて解決しました。 convertViewのタグから参照を取得することにより、以前のTextWatcherインスタンスを削除します。問題を完全に解決します。 CustomAdapterファイルで、次のような新しい内部クラスを設定します。

private static class ViewHolder {

        private TextChangedListener textChangedListener;
        private EditText productQuantity;

        public EditText getProductQuantity() {
            return productQuantity;
        }    

        public TextChangedListener getTextChangedListener() {
            return textChangedListener;
        }

        public void setTextChangedListener(TextChangedListener textChangedListener) {
            this.textChangedListener = textChangedListener;
        }
    }

次に、オーバーライドされたパブリックビューgetView(int position、View convertView、ViewGroup parent)メソッドで、以下のようなロジックを実装します。

@Override
public View getView(int position, View convertView, ViewGroup parent) {

     EditText productQuantity;
    TextChangedListener textChangedListener;

    if(convertView==null) {
        LayoutInflater mInflater = (LayoutInflater)
                context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        convertView = mInflater.inflate(R.layout.cart_offer_item, parent, false);

        productQuantity=(EditText)convertView.findViewById(R.id.productQuantity);
        addTextChangedListener(viewHolder, position);
        convertView.setTag(viewHolder);
    }
    else
    {
        ViewHolder viewHolder=(ViewHolder)convertView.getTag();
        productQuantity=viewHolder.getProductQuantity();
        removeTextChangedListener(viewHolder);
        addTextChangedListener(viewHolder, position);
    }

    return convertView;
}



private void removeTextChangedListener(ViewHolder viewHolder)
{
    TextChangedListener textChangedListener=viewHolder.getTextChangedListener();
    EditText productQuantity=viewHolder.getProductQuantity();
    productQuantity.removeTextChangedListener(textChangedListener);
}

private void addTextChangedListener(ViewHolder viewHolder, int position)
{
    TextChangedListener textChangedListener=new TextChangedListener(position);
    EditText productQuantity=viewHolder.getProductQuantity();
    productQuantity.addTextChangedListener(textChangedListener);
    viewHolder.setTextChangedListener(textChangedListener);
}

次に、次のようにTextWatcherクラスを実装します。

private class TextChangedListener implements TextWatcher
{
    private int position;
    TextChangedListener(int position)
    {
        this.position=position;
    }
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
    }
    @Override
    public void afterTextChanged(Editable s) {
    Log.d("check", "text changed in EditText");

    }
}

ConvertViewのタグから参照を取得することにより、以前のTextWatcherインスタンスを削除します。

10
gunjot singh

ビューホルダーに現在のテキストウォッチャーを保存すると、削除したいものを見つけることができます。

6
Lance H

TextViewクラスを拡張せずにこの状況を解決しました。

private ArrayList<TextWatcher> mEditTextWatcherList = new ArrayList<>();
private TextWatcher mTextWatcher1;
private TextWathcer mTextWatcher2;

mTextWathcer1 = 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) {}

    @Override
    public void afterTextChanged(Editable s) {}
};

mTextWathcer2 = 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) {}

    @Override
    public void afterTextChanged(Editable s) {}
};

@Override 
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity);

    setListener(mTextWatcher1);
    setListener(mTextWatcher2);

    removeListeners();
}

private setListener(TextWatcher listener) {
    mEditText.addTextChangedListener(listener);
    mEditTextWatcherList.add(listener);
}

private removeListeners() {
    for (TextWatcher t : mEditTextWatcherList)
        mEditText.removeTextChangedListener(t);

    mEditTextWatcherList.clear();
}

Xamarin/C#でも同じ問題が発生しました。このために、アイテムビューが「リサイクル」されるListView内のクリックイベントを管理するクラスを作成しました。

 public class ViewOnClickEventHandler: Java.Lang.Object
 {
    private List<EventHandler> EventList { get; set; }

    public void SetOnClickEventHandler(View view, EventHandler eventHandler)
    {
        if (view.Tag != null)
        {
            ViewOnClickEventHandler holder = ((ViewOnClickEventHandler)view.Tag);

            foreach (EventHandler evH in holder.EventList)
                view.Click -= evH;

            for (int i = 0; i < holder.EventList.Count; i++)
                holder.EventList[i] = null;

            holder.EventList.Clear();
        }

        EventList = new List<EventHandler>();
        EventList.Add(eventHandler);
        view.Click += eventHandler;
        view.Tag = this;
    }
}

ListView BaseAdapter GetItemメソッドで次のように使用できます。

       TextView myTextView = convertView.FindViewById<TextView>(Resource.Id.myTextView);

        ViewOnClickEventHandler onClick = new ViewOnClickEventHandler();
        onClick.SetOnClickEventHandler(myTextView, new EventHandler(delegate (object sender, EventArgs e)
        {
            // Do whatever you want with the click event
        }));

ViewOnClickEventHandlerクラスは、textviewの複数のイベントを処理します。 textchangeイベントのクラスを変更することもできます。それは同じ原則です。これが役立つことを願っています。

さようなら、nxexo007

1
nxexo007

テキストウォッチャーを削除するために私がしたことは非常に簡単です。テキストウォッチャーを配置する配列を作成しました。

final TextWatcher[] textWatchers = new TextWatcher[3];

私はそれらを追加しました:

final int CURRENT_PIN_CHECK = 0, NEW_PIN = 1, CONFIRM_PIN_CHECK = 2;

textWatchers[CURRENT_PIN_CHECK] = returnTextWatcherCheckPIN(CURRENT_PIN_CHECK);
textWatchers[NEW_PIN] = returnTextWatcherCheckPIN(NEW_PIN);
textWatchers[CONFIRM_PIN_CHECK] = returnTextWatcherCheckPIN(CONFIRM_PIN_CHECK);

私のreturnTextWatcherCheckPINメソッドは、afterTextChangedで異なるチェッカー(4つすべてのeditTextをチェックするswitchMethod)でtextWatcherをインスタンス化します。

次に、テキストウォッチャーを削除するたびに、配列から参照します。

etPin4.removeTextChangedListener(textWatchers[CURRENT_PIN_CHECK]);

デバッグ時にeditTextのリスナーサイズを確認します。

enter image description here

削除されました!これで私の問題は解決しました!

0
Kim Montano

ここにあるように: TextViewのCodeSearch すべてのリスナーを削除する方法はありません。唯一の方法は、登録に使用したウォッチャーを提供することです。

他のリスナーがすでに登録されている理由がまだ完全にはわかりません。ただし、EditTextをサブクラス化し、addTextChangedListener(..)をオーバーライドして、追加されたすべての参照のコピーを自分で保持してから、スーパークラスの実装に委任することができます。その後、すべてのリスナーを削除する追加のメソッドを提供することもできます。

さらに説明が必要な場合は連絡してください。

0
icyerasor

私は同様の問題に苦労しました。 textWatchersへの参照をArrayListに保存することで解決しました:

private final List<TextWatcher> textWatchersForProfileNameTextBox = new ArrayList<>();

public void addTextWatcherToProfileNameTextBox(TextWatcher textWatcher){
    textWatchersForProfileNameTextBox.add(textWatcher);
    getProfileNameTextView().addTextChangedListener(textWatcher);
}

public void removeAllTextWatchersFromProfileNameTextView(){
    while (!textWatchersForProfileNameTextBox.isEmpty())
        getProfileNameTextView().removeTextChangedListener(textWatchersForProfileNameTextBox.remove(0));
}
0
vatbub