Bagaimana cara menggunakan Single TextWatcher untuk beberapa EditTexts?

Jawaban:

190

Saya baru saja mengalami masalah ini. Saya menyelesaikannya dengan membuat implementasi kelas dalam TextWatcheryang mengambil View sebagai argumen. Kemudian, dalam implementasi metode, cukup aktifkan tampilan untuk melihat dari mana Editableasalnya

Pernyataan:

private class GenericTextWatcher implements TextWatcher{

    private View view;
    private GenericTextWatcher(View view) {
        this.view = view;
    }

    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

    public void afterTextChanged(Editable editable) {
        String text = editable.toString();
        switch(view.getId()){
            case R.id.name:
                model.setName(text);
                break;
            case R.id.email:
                model.setEmail(text);
                break;
            case R.id.phone:
                model.setPhone(text);
                break;
        }
    }
}

Pemakaian:

name = (EditText) findViewById(R.id.name);
name.setText(model.getName());
name.addTextChangedListener(new GenericTextWatcher(name));

email = (EditText) findViewById(R.id.email);
email.setText(model.getEmail());
email.addTextChangedListener(new GenericTextWatcher(email));

phone = (EditText) findViewById(R.id.phone);
phone.setText(model.getPhone());
phone.addTextChangedListener(new GenericTextWatcher(phone));
Sky Kelsey
sumber
1
Bisakah Anda jelaskan apa itu 'model' pada kode di atas dan di mana harus mendeklarasikannya?
YuDroid
33
jawaban ini tidak Single TextWatcher for multiple EditTexts. Ini adalah 3 instance dari satu kelas TextWatcher. Jadi 3 TextWatchers terpisah mengontrol 3 EditTexts.
Bobs
2
Solusi yang disarankan bukanlah satu TextWatcher untuk beberapa EditText. Periksa jawaban ini: stackoverflow.com/a/13787221/779408
Bobs
2
Berfungsi seperti pesona, menggabungkan ini dengan fragmen yang berisi elemen bentuk agar tidak kehilangan data saat mengubah orientasi aspek.
Mathijs Segers
1
@breceivemail Agar benar-benar adil, "TextWatcher tunggal" tidak selalu berarti satu instance, bisa juga menjadi satu kelas.
Malcolm
42

Jika Anda ingin menggunakan hanya afterTextChanged bandingkan yang dapat diedit:

@Override
public void afterTextChanged(Editable editable) {
    if (editable == mEditText1.getEditableText()) {
        // DO STH
    } else if (editable == mEditText2.getEditableText()) {
        // DO STH
    }
}
Tomasz
sumber
10
Ini hanya akan bekerja dengan benar jika Anda menggunakan ==bukan .equals().
Jarett Millard
2
Anda jenius! Ini hanya membandingkan pointer bukan nilai aktual yang disimpan di Editable! Iya!
Burak Tamtürk
3
bagaimana jika mEditText1 dan mEditText2 memiliki teks yang sama?
Bahas
@tuss itulah sebabnya mereka dibandingkan dengan referensi, bukan nilai
Joakim
1
@Tomasz Bagaimana cara kerjanya? Apakah Anda menerapkan TextWatcher? Tidakkah Anda harus mengganti tiga metode jika Anda melakukannya?
leonheess
10

Implementasi MultiTextWatcher

public class MultiTextWatcher {

    private TextWatcherWithInstance callback;

    public MultiTextWatcher setCallback(TextWatcherWithInstance callback) {
        this.callback = callback;
        return this;
    }

    public MultiTextWatcher registerEditText(final EditText editText) {
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                callback.beforeTextChanged(editText, s, start, count, after);
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                callback.onTextChanged(editText, s, start, before, count);
            }

            @Override
            public void afterTextChanged(Editable editable) {
                callback.afterTextChanged(editText, editable);
            }
        });

        return this;
    }

    interface TextWatcherWithInstance {
        void beforeTextChanged(EditText editText, CharSequence s, int start, int count, int after);

        void onTextChanged(EditText editText, CharSequence s, int start, int before, int count);

        void afterTextChanged(EditText editText, Editable editable);
    }
}

Pemakaian

    new MultiTextWatcher()
            .registerEditText(editText1)
            .registerEditText(editText2)
            .registerEditText(editText3)
            .setCallback(new TextWatcherWithInstance() {
                @Override
                public void beforeTextChanged(EditText editText, CharSequence s, int start, int count, int after) {
                    // TODO: Do some thing with editText
                }

                @Override
                public void onTextChanged(EditText editText, CharSequence s, int start, int before, int count) {
                    // TODO: Do some thing with editText
                }

                @Override
                public void afterTextChanged(EditText editText, Editable editable) {
                    // TODO: Do some thing with editText
                }
            });
Ilya Gazman
sumber
Mengapa Anda membuat kelas lain untuk hanya merantai mereka ?! Maksud saya, Anda masih belum tahu dari mana TextViewperubahan itu berasal.
Farid
10

Jika Anda ingin menggunakan perbandingan onTextChanged yanghashCode() disebutkan di bawah -

@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    if(charSequence.hashCode() == first_edit_text.getText().hashCode()){
        // do other things 
    }

    if(charSequence.hashCode() == second_edit_text.getText().hashCode()){
       // do other things 
    }

}

Atau

Jika Anda ingin menggunakan perbandingan afterTextChanged yangEditable disebutkan di bawah -

@Override
public void afterTextChanged(Editable editable) {
    if (editable == first_edit_text.getEditableText()) {
        // do other things 
    } else if (editable == second_edit_text.getEditableText()) {
       // do other things 
    }
}
Aman Jham
sumber
9

Ini akan bekerja dengan kode ini

TextWatcher watcher = new TextWatcher() {
  @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            //YOUR CODE
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            //YOUR CODE
        }

        @Override
        public void afterTextChanged(Editable s) {
          String outputedText = s.toString();

  mOutputText.setText(outputedText);

        }
    };

Kemudian tambahkan ini di oncreate

  mInputText.addTextChangedListener(watcher);
        e2.addTextChangedListener(watcher);
        e3.addTextChangedListener(watcher);
        e4.addTextChangedListener(watcher);
Asha Babu
sumber
Jadi dari mana mOutputText itu?
Kimi Chiu
5

Saya tahu ini masalah lama, dan ada keputusan yang tepat. Saya akan menulis sendiri, mungkin itu akan membantu seseorang.

Meniru contoh klasik di mana kami memiliki N EditText, dan kami ingin menampilkan tombol jika semua bidang terisi. Contoh ini masuk akal, terutama jika selanjutnya menggunakan validator untuk masing-masing.

Saya membuat contoh sehubungan dengan masalah ini, tetapi Anda dapat melakukan set apa pun

MultiEditText.class

public class MultiEditText extends AppCompatActivity{

EditText ed_1, ed_2, ed_3;
Button btn_ok;

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

    ed_1 = (EditText) findViewById(R.id.ed_1);
    ed_2 = (EditText) findViewById(R.id.ed_2);
    ed_3 = (EditText) findViewById(R.id.ed_3);
    btn_ok = (Button) findViewById(R.id.btn_ok);
    btn_ok.setEnabled(false);

    //if want more here can cycle interface List

     EditText[] edList = {ed_1, ed_2, ed_3};
     CustomTextWatcher textWatcher = new CustomTextWatcher(edList, btn_ok);
     for (EditText editText : edList) editText.addTextChangedListener(textWatcher);

    }
}

Ini terlihat sangat sederhana, sekarang

CustomTextWatcher.class

public class CustomTextWatcher implements TextWatcher {

View v;
EditText[] edList;

public CustomTextWatcher(EditText[] edList, Button v) {
    this.v = v;
    this.edList = edList;
}

@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) {
    for (EditText editText : edList) {
        if (editText.getText().toString().trim().length() <= 0) {
            v.setEnabled(false);
            break;
        }
        else v.setEnabled(true);
    }
  }
}

Saya akan menambahkan tata letak, jadi Anda tidak membuang waktu

multi_edit_text.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">

<EditText
    android:id="@+id/ed_1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp" />

<EditText
    android:id="@+id/ed_2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/ed_1"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp" />

<EditText
    android:id="@+id/ed_3"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/ed_2"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp" />

<Button
    android:id="@+id/btn_ok"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/ed_3"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp"
    android:text="OK" />
</RelativeLayout>
Shwarz Andrei
sumber
5

Buat kelas Anda mewarisi dari Activity dan implementasikan TextWatcher.

Kemudian melalui keajaiban polimorfisme, Anda hanya perlu berlangganan acara.

Ini tidak akan memberi tahu Anda apa yang diubah TextEdit, namun menggunakan kombinasi jawaban ini dan Sky Kelsey Anda dapat mengatasinya dengan baik.

public YourActivity extends Activity implements TextWatcher {

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

        //Subscribe to the events
        EditText txt1 = (EditText) findViewById(R.id.txt1);
        txt1.addTextChangedListener(this);

        EditText txt2 = (EditText) findViewById(R.id.txt2);
        txt2.addTextChangedListener(this);
    }

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

            EditText txt1 = (EditText) findViewById(R.id.txt1);
            EditText txt2 = (EditText) findViewById(R.id.txt2);
            // You probably only want the text value from the EditText. But you get the idea. 
                doStuff(txt1,txt2);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.calc, menu);
        return true;
    }

    @Override
    public void afterTextChanged(Editable s) {
        // TODO Auto-generated method stub
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // TODO Auto-generated method stub
    }
}
NitroxDM
sumber
3
TextWatcher watcher = 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) {
    }

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

Kemudian:

editText1.addTextChangedListener(watcher);
editText2.addTextChangedListener(watcher);
editText3.addTextChangedListener(watcher);
Cristian
sumber
2
(Peringatan posting merengek) Dia mungkin memiliki kode validasi yang sangat mirip untuk semua kontrol dan tidak ingin menyalin dan menempelkannya 3 kali :) Saya telah menekannya sebelumnya, mengapa mereka dapat mengirim kontrol yang menghasilkan klik pada onClickListener dan tidak pada hal-hal seperti TextWatcher ... Satu-satunya solusi yang dapat saya pikirkan adalah membuat 3 TextWatcher yang memanggil prosedur yang sama tetapi dengan penunjuk ke kontrol edit masing-masing.
Torp
1
@Torp, @bie: Jawaban ini mungkin menarik: stackoverflow.com/questions/4283062/… Tidak yakin ini benar-benar menyelesaikan masalah yang dinyatakan di sini, tetapi, seperti yang ditunjukkan, Anda dapat meminta CustomTextWatcher secara otomatis memanggil fungsi lain yang mengambil lulus Dapat diedit.
Kevin Coppock
3
public class MainActivity extends AppCompatActivity{
    EditText value1, value2;

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

        //instantiate EditText controls
        value1 = (EditText)findViewById(R.id.txtValue1);
        value2 = (EditText)findViewById(R.id.txtValue2);

        //set up text changed listener
        value1.addTextChangedListener(new TextChange(value1));               
        value2.addTextChangedListener(new TextChange(value2));                       

        //inner class
        private class TextChange implements TextWatcher {

             View view;
             private TextChange (View v) {
                 view = v;
             }

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

             }


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

                 switch (view.getId()) {
                     case R.id.txtValue1:
                         //insert your TextChangedListener codes here
                         break;

                     case R.id.txtValue2:
                         //insert your TextChangedListener codes here
                         break;
                 }
             }   
         }
     }
}
Ng Kian Keong
sumber
3

Ini adalah solusi saya untuk kotlin. Anda cukup menggunakan persamaan referensial (===) untuk memeriksa objek yang sama dan itu berfungsi dengan sempurna.

val mTextWatcher = object : TextWatcher {
        override fun afterTextChanged(et: Editable?) {

            when {
                et === et1.editableText -> {
                    Toast.makeText(this@MainActivity, "EditText 1", Toast.LENGTH_LONG).show()
                }
                et === et2.editableText -> {
                    Toast.makeText(this@MainActivity, "EditText 2", Toast.LENGTH_LONG).show()
                }

            }
        }

        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        }
        override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        }
    }
    et1.addTextChangedListener(mTextWatcher)
    et2.addTextChangedListener(mTextWatcher)
Shohan Ahmed Sijan
sumber
0

Saya tahu pertanyaan ini sudah lama, namun saya ingin membagikan salah satu solusi saya (di Kotlin). Solusi saya adalah perbaikan dari jawaban @Shwarz Andrei, alasan saya adalah bagaimana jika Anda ingin memanipulasi lebih banyak hal / objek.

Alih-alih melewati keduanya list of EditTextsdan a Buttonsebagai params, Anda hanya akan lulus list of editText. Kemudian di dalam kelas kustom Anda, Anda akan mengimplementasikan lambda seperti:

var hasFilled:((Boolean)->Unit)? = null 

Kemudian Anda akan mengatur atau menaikkannya di dalam afterTextChanged

override fun afterTextChanged(p0: Editable?) {
       for (edit in _editTextList) {
           if (edit?.text.toString().trim().isEmpty()) {
                 hasFilled?.invoke(false) //<-- here 
               break
           } else {
               hasFilled?.invoke(true) //<--- here 
           }
       }
   }

Jadi setiap kali, ada perubahan di beberapa EditText lambda Anda dipanggil

        val editTexts = listOf(emailEditText,passwordEditText) // your list of editText
        val textWatcher = customTextWatcher(editTexts) // initialize your custom object 
        editTexts.forEach { it -> it?.addTextChangedListener(textWatcher) } // each editText would listen for changes 


        textWatcher.hasFilled = { value ->  // now you have access to your lambda 
            if (value != true)  {
               // change the state of the button to unable 
              // do other things 
            } else {
              // change the state of the button to enable 
              // do other things 
            }
        }
Lamour
sumber
0

Inilah cara saya melakukannya:

Buat ArrayList dari EditTexts, dan kemudian gunakan loop for untuk menerapkan TextWatcher untuk semua EditTexts, jika Anda memiliki satu perilaku untuk semua editTexts, maka cukup terapkan di sana, jika Anda berperilaku khusus untuk beberapa editText tertentu, maka Anda dapat menggunakan if pernyataan untuk memilih dan diterapkan ke editTexts individu.

Ini kode saya:

ArrayList<EditText> editTexts = new ArrayList<>(); // Container list

editText1 = (EditText) findViewById(R.id.editText1);
editText2 = (EditText) findViewById(R.id.editText2);
editText3 = (EditText) findViewById(R.id.editText3);

editTexts.add(editText1); // editTexts[0]
editTexts.add(editText2); // editTexts[1]
editTexts.add(editText3); // editTexts[2]

for (final EditText editText : editTexts) { //need to be final for custom behaviors 
    editText.addTextChangedListener(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) {
            //Apply general behavior for all editTexts

            if (editText == editTexts.get(1)) {
                //Apply custom behavior just for this editText                           
            }
        }
    });

}

Semoga ini membantu

SamiHajjaj
sumber
Terima kasih atas jawabannya, tetapi apakah ini benar-benar satu-satunya cara untuk melakukannya? Maksud saya tampaknya agak rumit untuk sesuatu yang umum seperti onTextChangedpada EditText. Menambahkan onFocusChangeuntuk beberapa widget jauh lebih sederhana, karena ia meneruskan objek pengirim dengan pemanggilan metode. Kemudian Anda dapat memeriksa objek mana yang telah memicu panggilan tersebut dan menanganinya dari sana.
BdR