テキスト変更リスナー上のAndroid


265

私には2つのフィールドがあるという状況があります。field1field2。変更されたfield2ときに私がやりたいことはすべて空field1です。したがって、最後には1つのフィールドのみにコンテンツが含まれます。

field1 = (EditText)findViewById(R.id.field1);
field2 = (EditText)findViewById(R.id.field2);

field1.addTextChangedListener(new TextWatcher() {

   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) {
      field2.setText("");
   }
  });

field2.addTextChangedListener(new TextWatcher() {

   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) {
     field1.setText("");
   }
  });

にのみアタッチaddTextChangedListenerすると問題field1なく動作しますが、両方のフィールドにアタッチすると、アプリがクラッシュします。明らかに、彼らは無期限にお互いを変えようとするからです。一度field1変更するとfield2、この時点でクリアされ、 field2変更されるため、クリアfield1されます。

誰かが何か解決策を提案できますか?


新しいユーザーには、文字列のobservable-fieldを使用して双方向のデータバインディングを行ってください。ここで提供されるすべてのソリューションがstarting waiting blocking gc allocこのタイプのエラーを引き起こし、クラッシュやハングにつながる可能性があります。したがって、データバインディングに進んでください。安全で、グーグルによって今推奨される..
Maifee Ul Asad

回答:


460

チェックを追加して、フィールドのテキストが空でない場合(つまり、長さが0以外の場合)のみをクリアできます。

field1.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

   @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(s.length() != 0)
        field2.setText("");
   }
  });

field2.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

   @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(s.length() != 0)
         field1.setText("");
   }
  });

TextWatcher ここのドキュメント。

また、命名規則を尊重してください。


1
すべてのフィールドが変更された後に検出する方法。なぜなら、ボタンが押されると、フィールドが変更されるたびに検出されるからです。
RafaelGuimarães19年

20

私はこれが古いのを知っていますが、誰かがいつか再びこれに遭遇するかもしれません。

EditTextでsetTextを呼び出し、望まないときにonTextChangedが呼び出されるという同様の問題がありました。私の最初の解決策は、setText()を呼び出した後にコードを記述して、リスナーによるダメージを取り消すことでした。しかし、それはあまりエレガントではありませんでした。いくつかの調査とテストを行った後、getText()。clear()を使用すると、setText( "")とほぼ同じ方法でテキストがクリアされることがわかりましたが、テキストを設定していないため、リスナーは呼び出されません。私の問題を解決しました。すべてのsetText( "")呼び出しをgetText()。clear()に切り替えましたが、包帯は必要なくなったので、問題が解決するかもしれません。

これを試して:

Field1 = (EditText)findViewById(R.id.field1);
Field2 = (EditText)findViewById(R.id.field2);

Field1.addTextChangedListener(new TextWatcher() {

   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) {
      Field2.getText().clear();
   }
  });

Field2.addTextChangedListener(new TextWatcher() {

   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) {
     Field1.getText().clear();
   }
  });

11

Android開発にKotlinを使用している場合は、次のTextChangedListener()コードを使用して追加できます。

myTextField.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) {}
    })

5

答えには少し遅れますが、ここに再利用可能なソリューションがあります:

/**
 * An extension of TextWatcher which stops further callbacks being called as 
 * a result of a change happening within the callbacks themselves.
 */
public abstract class EditableTextWatcher implements TextWatcher {

    private boolean editing;

    @Override
    public final void beforeTextChanged(CharSequence s, int start, 
                                                    int count, int after) {
        if (editing)
            return;

        editing = true;
        try {
            beforeTextChange(s, start, count, after);
        } finally {
            editing = false;
        }
    }

    protected abstract void beforeTextChange(CharSequence s, int start, 
                                                     int count, int after);

    @Override
    public final void onTextChanged(CharSequence s, int start, 
                                                int before, int count) {
        if (editing)
            return;

        editing = true;
        try {
            onTextChange(s, start, before, count);
        } finally {
            editing = false;
        }
    }

    protected abstract void onTextChange(CharSequence s, int start, 
                                            int before, int count);

    @Override
    public final void afterTextChanged(Editable s) {
        if (editing)
            return;

        editing = true;
        try {
            afterTextChange(s);
        } finally {
            editing = false;
        }
    }

    public boolean isEditing() {
        return editing;
    }

    protected abstract void afterTextChange(Editable s);
}

したがって、上記を使用した場合、setText()TextWatcher内で発生する呼び出しは、TextWatcherが再度呼び出されることにはなりません。

/**
 * A setText() call in any of the callbacks below will not result in TextWatcher being 
 * called again.
 */
public class MyTextWatcher extends EditableTextWatcher {

    @Override
    protected void beforeTextChange(CharSequence s, int start, int count, int after) {
    }

    @Override
    protected void onTextChange(CharSequence s, int start, int before, int count) {
    }

    @Override
    protected void afterTextChange(Editable s) {
    }
}

5

私も同じ問題に直面し、stackOverflow例外が発生し続けており、次の解決策が考えられます。

edt_amnt_sent.addTextChangedListener(new TextWatcher() {    
    @Override
    public void afterTextChanged(Editable s) {
        if (skipOnChange)
            return;

        skipOnChange = true;
        try {
            //method
        } catch (NumberFormatException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            skipOnChange = false;
        }
    }
});

edt_amnt_receive.addTextChangedListener(new TextWatcher() {

    @Override
    public void afterTextChanged(Editable s) {

        if (skipOnChange)
            return;

        skipOnChange = true;
        try {
            //method
        } catch (NumberFormatException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            skipOnChange = false;
        }
    }
});

最初に宣言されたブールskipOnChange = false;


1
「スタックフル」とは、スタックオーバーフローを意味すると思います;)
Aドロイド

4

また、hasFocus()メソッドを使用することもできます。

public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     if (Field2.hasfocus()){
         Field1.setText("");
     }
   }

ユーザーが入力した温度スケールを変換するために私が取り組んでいた大学の課題に対してこれをテストしました。完全に機能し、それははるかに簡単です。


1
ユーザーが入力したときのeditText.setTextはどうですか?EditTextはこの場合に焦点を当てています
Evgenii Vorobei 2018

最高のソリューション。
Syed Hissaan

3

別の文字列EditTextを空に設定する前に文字列を確認してください。Field1空の場合、なぜ再び( "")に変更する必要がありますか?あなたはあなたの文字列のサイズをs.lenght()または他の解決策で確認できます

文字列の長さを確認できる別の方法は次のとおりです。

String sUsername = Field1.getText().toString();
if (!sUsername.matches(""))
{
// do your job
}

2

私はこれのために独自の拡張機能を作成しました。(コトリン)

あなたはそのようにしか書くことができません:

editText.customAfterTextChanged { editable -> 
    //You have accessed the editable object. 
}

私の拡張子:

fun EditText.customAfterTextChanged(action: (Editable?)-> Unit){
    this.addTextChangedListener(object : TextWatcher {
       override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
       override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
       override fun afterTextChanged(editable: Editable?) {
        action(editable)
    }
})}

2
editText.addTextChangedListener(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) {
                if (noteid != -1) {
                    MainActivity.notes.set(noteid, String.valueOf(charSequence));
                    MainActivity.arrayAdapter.notifyDataSetChanged();
                }
            }
            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

このコードのノートIDは、基本的には、インデントに入れられるか、インデントを介して渡される引数です。

  Intent intent = getIntent();
         noteid = intent.getIntExtra("noteid", -1);

より明確に理解したい場合、欠点のコードは基本的に追加のコードです。

how to make the menu or insert the menu in our code , 
    create the  menu folder this the folder created by going into the raw
    ->rightclick->
    directory->name the folder as you wish->
    then click on the directory formed->
    then click on new file and then name for file as you wish ie the folder name file
    and now type the 2 lines code in it and see the magic.

編集目的でNoteEditor.javaという名前の新しいアクティビティコード。私のアプリは基本的にはノートアプリです。

package com.example.elavi.notes;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.Toast;

import static android.media.CamcorderProfile.get;
public class NoteEditorActivity extends AppCompatActivity {
    EditText editText;
    int noteid;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_note_editor);
        editText = findViewById(R.id.editText);
        Intent intent = getIntent();
         noteid = intent.getIntExtra("noteid", -1);
        if (noteid != -1) {
            String text = MainActivity.notes.get(noteid);
            editText.setText(text);

           Toast.makeText(getApplicationContext(),"The arraylist content is"+MainActivity.notes.get(noteid),Toast.LENGTH_SHORT).show();
        }
        else
        {
            Toast.makeText(getApplicationContext(),"Here we go",Toast.LENGTH_SHORT).show();
            MainActivity.notes.add("");
            noteid=MainActivity.notes.size()-1;
        }
        editText.addTextChangedListener(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) {
                if (noteid != -1) {
                    MainActivity.notes.set(noteid, String.valueOf(charSequence));
                    MainActivity.arrayAdapter.notifyDataSetChanged();
                }
            }
            @Override
            public void afterTextChanged(Editable editable) {

            }
        });
    }
}

1

Kotlin単に使用KTXの拡張機能を: (それは使用していますTextWatcher

yourEditText.doOnTextChanged { text, start, count, after -> 
        // action which will be invoked when the text is changing
    }


インポートcore-KTX

implementation "androidx.core:core-ktx:1.2.0"

1

テキストを編集する直前にフィールドのTextWatcherを削除し、テキストを編集した後にフィールドを元に戻すことができます。

名前を付けるために、field1field2の両方のテキストウォッチャーを別々の変数として宣言します。たとえば、field1の場合

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

    @Override
    public void afterTextChanged(Editable s) {
    }

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

    }

};

:その名前を使用してウォッチャーを追加する field1.addTextChangedListener(Field_1_Watcher)ためのフィールド1、および field2.addTextChangedListener(Field_2_Watcher)のためのフィールド2

field2テキストを変更する前に、TextWatcherを削除 field2.removeTextChangedListener(Field_2_Watcher) します。テキストを変更します。 field2.setText("")

次に、TextWatcherを再度追加します。 field2.addTextChangedListener(Field_2_Watcher)

他のフィールドについても同じようにします


-3

onCreateメソッドで背景を動的に追加します。

getWindow().setBackgroundDrawableResource(R.drawable.background);

また、XMLから背景を削除します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.