android EditText - acara mengetik selesai

122

Saya ingin melihat acara ketika pengguna selesai mengedit EditText.

Bagaimana caranya?

eddyuk
sumber
1
@PadmaKumar Cara paling alami adalah jika fokus hilang pada EditText - maka pengguna pasti sudah selesai, namun dari pengalaman tampaknya tidak semua widget android benar-benar mengambil fokus (saya punya masalah dengan Pemutar dan Tombol) - jadi widget lain mungkin tidak kehilangan fokus ...
AgentKnopf
3
mengapa platform sebesar itu membiarkan kita berurusan dengan fungsi sederhana semacam ini? google tidak akan kehilangan apa pun jika mereka menambahkan fitur utama tersebut ke pustaka dukungan mereka setidaknya
MBH
Jika Anda tahu panjang persis string yang akan dimasukkan pengguna, dapatkan teksnya di afterTextChanged. Contoh:override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Shylendra Madda
2
Saya menggaruk-garuk kepala heran mengapa ini sangat sulit di Android sehingga kami (termasuk saya) perlu mencari dan memulai diskusi online dan banyak solusi berbeda dengan 10+ baris kode ..?
nsandersen

Jawaban:

118

Setelah pengguna selesai mengedit, dia akan menekan DoneatauEnter

((EditText)findViewById(R.id.youredittext)).setOnEditorActionListener(
    new EditText.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            if (actionId == EditorInfo.IME_ACTION_SEARCH ||
                    actionId == EditorInfo.IME_ACTION_DONE ||
                    event != null &&
                    event.getAction() == KeyEvent.ACTION_DOWN &&
                    event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
                if (event == null || !event.isShiftPressed()) {
                   // the user is done typing. 

                   return true; // consume.
                }                
            }
            return false; // pass on to other listeners. 
        }
    }
);
Reno
sumber
50
Bisakah kamu yakin tentang itu? Saya memiliki kebiasaan memasuki / ke bidang yang dapat diedit berikutnya - saya hampir tidak pernah menekan Enter / Selesai - dan apa yang telah saya lihat dari pelanggan kami, mereka juga tidak ... Saya berbicara tentang daftar Teks Edit / Kotak Kombo, dll. . Jika Anda hanya memberi pengguna satu bidang Input dan memaksanya untuk menekan tombol sebelum dia dapat maju ke bidang lain maka itu jelas lain cerita ...
AgentKnopf
5
Ingat, Anda juga harus menyetel android: singleLine = "true" untuk teks edit Anda. Terima kasih kepada stackoverflow.com/questions/15901863/…
steven smith
1
Solusi bagus tetapi bisa macet dengan pointer nol ... 'event' bisa menjadi null pada tindakan Selesai jadi event.isShiftPressed () lumpuh. Jika Anda menggunakan ini tambahkan pemeriksaan penunjuk null.
Georgie
Edit ditambahkan untuk memeriksa null "Event".
Word Rearranger
3
bagaimana jika Anda menekan tombol KEMBALI yang menutup keyboard?
pengguna347187
183

Cara yang lebih baik, Anda juga dapat menggunakan pendengar EditText onFocusChange untuk memeriksa apakah pengguna telah melakukan pengeditan: (Tidak perlu bergantung pada pengguna yang menekan tombol Selesai atau Enter pada Soft keyboard)

 ((EditText)findViewById(R.id.youredittext)).setOnFocusChangeListener(new OnFocusChangeListener() {

    @Override
    public void onFocusChange(View v, boolean hasFocus) {

      // When focus is lost check that the text field has valid values.

      if (!hasFocus) { {
         // Validate youredittext
      }
    }
 });

Catatan: Untuk lebih dari satu EditText, Anda juga dapat membiarkan kelas Anda mengimplementasikan View.OnFocusChangeListenerlalu menyetel listener untuk Anda masing-masing EditText dan memvalidasinya seperti di bawah ini

((EditText)findViewById(R.id.edittext1)).setOnFocusChangeListener(this);
((EditText)findViewById(R.id.edittext2)).setOnFocusChangeListener(this);

    @Override
    public void onFocusChange(View v, boolean hasFocus) {

      // When focus is lost check that the text field has valid values.

      if (!hasFocus) {
        switch (view.getId()) {
           case R.id.edittext1:
                 // Validate EditText1
                 break;
           case R.id.edittext2:
                 // Validate EditText2
                 break;
        }
      }
    }
Vinayak Bevinakatti
sumber
60
Ini tidak berfungsi jika hanya ada satu yang bisa difokuskan EditText. Itu tidak akan pernah kehilangan fokus.
Bart Friederichs
Apa cara terbaik jika kita hanya memiliki satu EditText? Apakah saya harus menggunakan onEditorAction?
Tux
3
Jika hanya ada satu EditText, Anda memvalidasi apa pun yang dilakukan pengguna untuk meninggalkan layar.
Christine
Saya mencoba ini tetapi tidak berhasil. Setiap kali saya menekan enter, saya akan mendapat pesan seperti ini: W/ViewRootImpl: Cancelling event due to no window focus: MotionEvent { action=ACTION_CANCEL, actionButton=0, id[0]=0, x[0]=605.52246, y[0]=969.4336, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=238238, downTime=235422, deviceId=0, source=0x1002 }Meskipun saya mengetik sesuatu. Ini adalah teks edit yang hanya menerima angka.
ahitt6345
1
Ada titik samping dalam menggunakan pendengar OnFocusChange: ini tidak akan dipanggil jika EditText memiliki fokus dan perangkat diputar! Saya menyelesaikannya dengan meletakkan someOtherView.requestFocus () di Aktivitas onPause (). (before super.onPause ()) Dengan cara itu aman bahwa EditText kehilangan fokus dan listener dipanggil.
allofmex
60

Saya pribadi lebih suka pengiriman otomatis setelah pengetikan berakhir. Inilah cara Anda mendeteksi peristiwa ini.

Deklarasi dan inisialisasi:

private Timer timer = new Timer();
private final long DELAY = 1000; // in ms

Pendengar di misalnya onCreate ()

EditText editTextStop = (EditText) findViewById(R.id.editTextStopId);
    editTextStop.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
        }
        @Override
        public void onTextChanged(final CharSequence s, int start, int before,
                int count) {
            if(timer != null)
                timer.cancel();
        }
        @Override
        public void afterTextChanged(final Editable s) {
            //avoid triggering event when text is too short
            if (s.length() >= 3) {              

                timer = new Timer();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        // TODO: do what you need here (refresh list)
                        // you will probably need to use
                        // runOnUiThread(Runnable action) for some specific
                        // actions
                        serviceConnector.getStopPoints(s.toString());
                    }

                }, DELAY);
            }
        }
    });

Jadi, ketika teks diubah, pengatur waktu mulai menunggu perubahan berikutnya terjadi. Ketika terjadi, pengatur waktu dibatalkan dan kemudian dimulai sekali lagi.

ZimaXXX
sumber
11
ini luar biasa, tetapi berhati-hatilah karena pengatur waktu dapat menyebabkan kebocoran memori, jadi gunakan Handlersaja
Moh Mah
Ini bagus, Thansk.
VipPunkJoshers Droopy
apa itu serviceConnector?
altruistik
@altruistic Ini hanya bagian dari kode saya yang saya ekstrusi jawabannya. Ini tempat di mana logika harus pergi.
ZimaXXX
21

Anda dapat melakukannya menggunakan setOnKeyListener atau menggunakan textWatcher seperti:

Atur pengamat teks editText.addTextChangedListener(textWatcher);

lalu panggil

private TextWatcher textWatcher = new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            //after text changed
        }

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

        @Override
        public void afterTextChanged(Editable s) {

        }
    };
Meredup
sumber
27
Saya khawatir ini bukan solusi (lengkap) - textWatcher akan aktif setelah setiap pengeditan - jika Anda mengetik halo, ini akan diaktifkan untuk h, e, l, l, dan o - ia tidak benar-benar tahu kapan pengguna "selesai" . Akan sangat bagus jika TextWatcher benar-benar tahu kapan widget kehilangan fokus dan pengguna pindah ...
AgentKnopf
4

Meskipun banyak jawaban memang menunjuk ke arah yang benar, saya pikir tidak ada dari mereka yang menjawab apa yang dipikirkan oleh penulis pertanyaan itu. Atau setidaknya saya memahami pertanyaan itu secara berbeda karena saya sedang mencari jawaban untuk masalah serupa. Masalahnya adalah "Bagaimana mengetahui kapan pengguna berhenti mengetik tanpa dia menekan tombol" dan memicu beberapa tindakan (misalnya pelengkapan otomatis). Jika Anda ingin melakukan ini, mulailah Timer di onTextChanged dengan penundaan yang Anda anggap pengguna berhenti mengetik (misalnya 500-700ms), untuk setiap huruf baru saat Anda memulai timer, batalkan yang sebelumnya (atau setidaknya gunakan semacam tandai bahwa ketika mereka mencentang mereka tidak melakukan apa-apa). Berikut kode yang mirip dengan yang saya gunakan:

new Timer().schedule(new TimerTask() {
  @Override
  public void run() {
     if (!running) {                            
        new DoPost().execute(s.toString());
  });
 }
}, 700);

Perhatikan bahwa saya memodifikasi menjalankan bendera boolean di dalam tugas async saya (Tugas mendapatkan json dari server untuk pelengkapan otomatis).

Juga perlu diingat bahwa ini menciptakan banyak tugas pengatur waktu (saya pikir mereka dijadwalkan pada Thread yang sama tetapi Anda harus memeriksanya), jadi mungkin ada banyak tempat untuk diperbaiki tetapi pendekatan ini juga berfungsi dan intinya adalah Anda harus gunakan Pewaktu karena tidak ada "Pengguna berhenti mengetik acara"

Igor Čordaš
sumber
Bisakah Anda memberikan informasi lebih lanjut dan kode contoh tentang ini?
John Ernest Guadalupe
Inti dari kode ada di jawaban, untuk contoh yang lebih detail silahkan lihat jawaban oleh ZimaXXX di halaman yang sama yang menggunakan pendekatan yang sama. Saya tidak tahu info apa lagi yang bisa saya tambahkan, jika Anda dapat menentukan apa yang tidak jelas saya akan mencoba menambahkan detail.
Igor Čordaš
4

@Reno dan @Vinayak B menjawab bersama jika Anda ingin menyembunyikan keyboard setelah tindakan

textView.setOnEditorActionListener(new EditText.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE) {
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(textView.getWindowToken(), 0);
            return true;
        }
        return false;
    }
});

textView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (!hasFocus) {
             // your action here
        }
    }
});
Tyler Davis
sumber
3

Pendekatan yang berbeda ... berikut ini contohnya: Jika pengguna mengalami penundaan 600-1000ms saat mengetik, Anda mungkin menganggap dia berhenti.

 myEditText.addTextChangedListener(new TextWatcher() {
             
            private String s;
            private long after;
			private Thread t;
            private Runnable runnable_EditTextWatcher = new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        if ((System.currentTimeMillis() - after) > 600)
                        {
                            Log.d("Debug_EditTEXT_watcher", "(System.currentTimeMillis()-after)>600 ->  " + (System.currentTimeMillis() - after) + " > " + s);
                            // Do your stuff
                            t = null;
                            break;
                        }
                    }
                }
            };
            
            @Override
            public void onTextChanged(CharSequence ss, int start, int before, int count) {
                s = ss.toString();
            }
            
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            
            @Override
            public void afterTextChanged(Editable ss) {
                after = System.currentTimeMillis();
                if (t == null)
                {
                    t = new Thread(runnable_EditTextWatcher);
                      t.start();
                }
            }
        });

Cristi Maris
sumber
2

Oke, ini pasti berhasil 100%.

Pertama, Anda perlu menyiapkan pendengar jika keyboard ditampilkan atau disembunyikan. Jika keyboard ditampilkan maka kemungkinan pengguna sedang mengetik, jika tidak selesai mengetik.

final View activityRootView = findViewById(android.R.id.content);
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {

                    Rect r = new Rect();
                    //r will be populated with the coordinates of your view that area still visible.
                    activityRootView.getWindowVisibleDisplayFrame(r);

                    int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
                    if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...

                        isTyping = true;
                    } else {
//to make sure this will call only once when keyboard is hide.
                        if(isTyping){
                            isTyping = false;
                        }
                    }
            }
        });
Krit
sumber
1
bagaimana dengan beberapa pengeditan teks? Dan heightDiff > 100barangnya menakutkan imho.
Bondax
Tidak masalah, ini berfungsi dengan baik. Lihat stackoverflow.com/questions/2150078/…
Krit
2

Saya memecahkan masalah ini dengan cara ini. Saya menggunakan kotlin.

        var timer = Timer()
        var DELAY:Long = 2000

        editText.addTextChangedListener(object : TextWatcher {

            override fun afterTextChanged(s: Editable?) {
                Log.e("TAG","timer start")
                timer = Timer()
                timer.schedule(object : TimerTask() {
                    override fun run() {
                        //do something
                    }
                }, DELAY)
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                Log.e("TAG","timer cancel ")
                timer.cancel() //Terminates this timer,discarding any currently scheduled tasks.
                timer.purge() //Removes all cancelled tasks from this timer's task queue.
            }
        })
Fahed Hermoza
sumber
0

Saya memiliki masalah yang sama dan tidak ingin bergantung pada pengguna yang menekan Selesai atau Enter.

Upaya pertama saya adalah menggunakan pendengar onFocusChange, tetapi ternyata EditText saya mendapatkan fokus secara default. Saat pengguna menekan beberapa tampilan lain, onFocusChange dipicu tanpa pengguna pernah menetapkannya sebagai fokus.

Solusi berikutnya melakukannya untuk saya, di mana onFocusChange dilampirkan jika pengguna menyentuh EditText:

final myEditText = new EditText(myContext); //make final to refer in onTouch
myEditText.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            myEditText.setOnFocusChangeListener(new OnFocusChangeListener() {

                @Override
                public void onFocusChange(View v, boolean hasFocus) {
                    if(!hasFocus){
                        // user is done editing
                    }
                }
            }
        }
}

Dalam kasus saya, ketika pengguna selesai mengedit layar dirender, dengan demikian memperbarui objek myEditText. Jika objek yang sama disimpan, Anda mungkin harus menghapus listener onFocusChange di onFocusChange untuk mencegah masalah onFocusChange yang dijelaskan di awal posting ini.

Jos
sumber
Anda menyetel pendengar perubahan fokus setiap kali peristiwa sentuh terjadi, yang akan berlangsung beberapa kali dalam satu detik. Jangan lakukan ini.
jsonfry
0

Saya mengalami masalah yang sama saat mencoba menerapkan 'sekarang mengetik' di aplikasi obrolan. coba untuk memperluas EditText sebagai berikut:

public class TypingEditText extends EditText implements TextWatcher {

private static final int TypingInterval = 2000;


public interface OnTypingChanged {
    public void onTyping(EditText view, boolean isTyping);
}
private OnTypingChanged t;
private Handler handler;
{
    handler = new Handler();
}
public TypingEditText(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    this.addTextChangedListener(this);
}

public TypingEditText(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.addTextChangedListener(this);
}

public TypingEditText(Context context) {
    super(context);
    this.addTextChangedListener(this);
}

public void setOnTypingChanged(OnTypingChanged t) {
    this.t = t;
}

@Override
public void afterTextChanged(Editable s) {
    if(t != null){
        t.onTyping(this, true);
        handler.removeCallbacks(notifier);
        handler.postDelayed(notifier, TypingInterval);
    }

}

private Runnable notifier = new Runnable() {

    @Override
    public void run() {
        if(t != null)
            t.onTyping(TypingEditText.this, false);
    }
};

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


@Override
public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { }

}

Nadav
sumber
0

Saya mengakhirinya dengan masalah yang sama dan saya tidak dapat menggunakan solusi dengan onEditorAction atau onFocusChange dan tidak ingin mencoba pengatur waktu. Timer terlalu berbahaya untuk rasa, karena semua utas dan terlalu tidak terduga, karena Anda tidak tahu kapan kode Anda dijalankan.

OnEditorAction tidak menangkap saat pengguna pergi tanpa menggunakan tombol dan jika Anda menggunakannya harap perhatikan bahwa KeyEvent bisa menjadi null. Fokus tidak dapat diandalkan di kedua ujungnya, pengguna bisa mendapatkan fokus dan keluar tanpa memasukkan teks apa pun atau memilih bidang dan pengguna tidak perlu meninggalkan bidang EditText terakhir.

Solusi saya menggunakan onFocusChange dan sebuah flag disetel ketika pengguna mulai mengedit teks dan sebuah fungsi untuk mendapatkan teks dari tampilan fokus terakhir, yang saya panggil saat dibutuhkan.

Saya hanya menghapus fokus pada semua bidang teks saya untuk mengelabui kode tampilan teks cuti, Kode clearFocus hanya dijalankan jika bidang memiliki fokus. Saya memanggil fungsi di onSaveInstanceState jadi saya tidak perlu menyimpan bendera (mEditing) sebagai status tampilan EditText dan saat tombol penting diklik dan saat aktivitas ditutup.

Hati-hati dengan TexWatcher karena sering dipanggil saya menggunakan kondisi fokus agar tidak bereaksi ketika kode onRestoreInstanceState memasukkan teks. saya

final EditText mEditTextView = (EditText) getView();

    mEditTextView.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) {
            if (!mEditing && mEditTextView.hasFocus()) {
                mEditing = true;
            }
        }
    });
    mEditTextView.setOnFocusChangeListener(new View.OnFocusChangeListener() {

        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus && mEditing) {
                mEditing = false;
                ///Do the thing
            }
        }
    });
protected void saveLastOpenField(){
    for (EditText view:getFields()){
            view.clearFocus();
    }
}
Rezder
sumber
0

Saya telah melakukan sesuatu seperti kelas abstrak ini yang dapat digunakan untuk menggantikan tipe TextView.OnEditorActionListener.

abstract class OnTextEndEditingListener : TextView.OnEditorActionListener {

    override fun onEditorAction(textView: TextView?, actionId: Int, event: KeyEvent?): Boolean {

        if(actionId == EditorInfo.IME_ACTION_SEARCH ||
                actionId == EditorInfo.IME_ACTION_DONE ||
                actionId == EditorInfo.IME_ACTION_NEXT ||
                event != null &&
                event.action == KeyEvent.ACTION_DOWN &&
                event.keyCode == KeyEvent.KEYCODE_ENTER) {

            if(event == null || !event.isShiftPressed) {
                // the user is done typing.
                return onTextEndEditing(textView, actionId, event)
            }
        }
        return false // pass on to other listeners
    }

    abstract fun onTextEndEditing(textView: TextView?, actionId: Int, event: KeyEvent?) : Boolean
}
Michał Ziobro
sumber
0

Sederhana untuk memicu selesai mengetik di EditText

bekerja untuk saya, jika Anda menggunakan java mengubahnya

Di Kotlin

youredittext.doAfterTextChanged { searchTerm ->
val currentTextLength = searchTerm?.length
    Handler().postDelayed({
        if (currentTextLength == searchTerm?.length) {
            // your code 
           Log.d("aftertextchange", "ON FINISH TRIGGER")
          }
       }, 3000)
}
Kharis Azhar
sumber