Kullanıcı EditText'i düzenlemeyi bitirdiğinde bir olay yakalamak istiyorum.
Nasıl yapılabilir?
override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Kullanıcı EditText'i düzenlemeyi bitirdiğinde bir olay yakalamak istiyorum.
Nasıl yapılabilir?
override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Yanıtlar:
Kullanıcı düzenlemeyi bitirdiğinde, Done
veya tuşuna basacaktır.Enter
((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.
}
}
);
Daha iyi bir yol, kullanıcının düzenleme yapıp yapmadığını kontrol etmek için EditText onFocusChange dinleyicisini de kullanabilirsiniz: ( Kullanıcının Dokunmatik klavyede Bitti veya Gir düğmesine basmasına güvenmeniz gerekmez )
((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
}
}
});
Not: Birden fazla EditText için, sınıfınızın uygulamasına izin verebilir, View.OnFocusChangeListener
ardından dinleyicileri her biriniz için EditText ayarlayabilir ve aşağıdaki gibi doğrulayabilirsiniz.
((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;
}
}
}
EditText
. Odağını asla kaybetmeyecek.
EditText
? Kullanmak zorunda onEditorAction
mıyım?
EditText
varsa, kullanıcının ekrandan ayrılmak için ne yapacağını doğrularsınız.
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 }
bastığımda bana şuna benzer bir mesaj veriyordu: Bir şey yazmış olsam bile. Bu sadece sayıları kabul eden bir edittext.
Ben şahsen yazım bittikten sonra otomatik göndermeyi tercih ediyorum. İşte bu olayı nasıl tespit edebileceğiniz.
Bildirimler ve başlatma:
private Timer timer = new Timer();
private final long DELAY = 1000; // in ms
Örneğin onCreate () 'de dinleyici
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);
}
}
});
Bu nedenle, metin değiştirildiğinde, zamanlayıcı sonraki değişikliklerin gerçekleşmesini beklemeye başlar. Oluştuklarında zamanlayıcı iptal edilir ve ardından tekrar başlatılır.
Handler
bunun yerine kullanın
Bunu setOnKeyListener kullanarak veya aşağıdaki gibi bir textWatcher kullanarak yapabilirsiniz:
Metin izleyiciyi ayarla editText.addTextChangedListener(textWatcher);
sonra ara
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) {
}
};
Pek çok yanıt doğru yönü işaret etse de hiçbirinin sorunun yazarının ne düşündüğünü yanıtladığını sanmıyorum. Ya da en azından soruyu farklı anladım çünkü benzer soruna cevap arıyordum. Sorun, "Kullanıcı bir düğmeye basmadan yazmayı bıraktığında nasıl anlaşılır" ve bazı eylemleri tetikler (örneğin, otomatik tamamlama). Bunu yapmak istiyorsanız, Timer'ı onTextChanged'da, kullanıcının yazmayı durdurduğunu düşüneceğiniz bir gecikmeyle (örneğin, 500-700ms) başlatın, zamanlayıcıyı başlattığınızda her yeni harf için öncekini iptal edin (veya en azından bir tür işaretlediklerinde hiçbir şey yapmadıklarını işaretleyin). İşte kullandığıma benzer kod:
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if (!running) {
new DoPost().execute(s.toString());
});
}
}, 700);
Zaman uyumsuz görevimde çalışan boole bayrağını değiştirdiğimi unutmayın (Görev, json'u otomatik tamamlama için sunucudan alır).
Ayrıca, bunun birçok zamanlayıcı görevi oluşturduğunu da unutmayın (sanırım bunlar aynı İş Parçacığında planlanmışlardır ancak bunu kontrol etmeleri gerekir), bu nedenle muhtemelen iyileştirilecek birçok yer vardır, ancak bu yaklaşım da işe yarıyor ve sonuç olarak "Kullanıcı yazmayı durdurdu" olmadığı için bir Zamanlayıcı kullanın
Eylemden sonra klavyeyi gizlemek istiyorsanız hem @ Reno hem de @ Vinayak B birlikte yanıt verir
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
}
}
});
Farklı bir yaklaşım ... işte bir örnek: Eğer kullanıcı yazarken 600-1000 ms gecikme yaşıyorsa, durduğunu düşünebilirsiniz.
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();
}
}
});
Tamam, bu kesinlikle% 100 çalışacak.
Öncelikle klavye gösteriliyorsa veya gizleniyorsa dinleyiciyi ayarlamanız gerekecek. Klavye gösteriliyorsa, muhtemelen kullanıcı yazıyordur, aksi halde yazmayı bitirmiştir.
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;
}
}
}
});
heightDiff > 100
şeyler korkunç bir imho.
Bu sorunu bu şekilde çözdüm. Kotlin kullandım.
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.
}
})
Aynı sorunu yaşadım ve Done veya Enter tuşuna basan kullanıcıya güvenmek istemedim.
İlk girişimim onFocusChange dinleyicisini kullanmaktı, ancak varsayılan olarak odağı EditText'im aldı. Kullanıcı başka bir görünüme bastığında, kullanıcı ona odak atamadan onFocusChange tetiklendi.
Bir sonraki çözüm benim için yaptı, kullanıcı EditText'e dokunduysa onFocusChange eklendi:
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
}
}
}
}
}
Benim durumumda, kullanıcı düzenlemeyi bitirdiğinde ekran yeniden oluşturulmuş ve böylece myEditText nesnesi yenilenmiştir. Aynı nesne tutulursa, bu gönderinin başında açıklanan onFocusChange sorununu önlemek için muhtemelen onFocusChange dinleyicisini onFocusChange'den kaldırmanız gerekir.
Sohbet uygulamasında 'şimdi yazarak' uygulamaya çalışırken aynı sorunu yaşadım. EditText'i aşağıdaki gibi genişletmeyi deneyin:
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) { }
}
Onu aynı problemle bitirdim ve çözümü onEditorAction veya onFocusChange ile kullanamadım ve zamanlayıcıyı denemek istemedim. Bir zamanlayıcı, tüm iş parçacıkları nedeniyle may tadı için çok tehlikelidir ve kodun ne zaman yürütüldüğünü bilmediğiniz için çok öngörülemez.
Kullanıcı bir düğme kullanmadan ayrıldığında onEditorAction yakalanmaz ve eğer onu kullanırsanız, lütfen KeyEvent'in boş olabileceğini unutmayın. Odak her iki uçta da güvenilmezdir, kullanıcı herhangi bir metin girmeden veya alanı seçmeden odaklanabilir ve ayrılabilir ve kullanıcının son Metin Düzenleme alanını terk etmesi gerekmez.
Çözümüm, kullanıcı metni düzenlemeye başladığında onFocusChange ve bir bayrak seti ve gerektiğinde son odaklanmış görünümden metni almak için bir işlev kullanıyor.
Bırakılan metin görüntüleme kodunu kandırmak için tüm metin alanlarımdaki odağı temizlerim, clearFocus kodu yalnızca alanda odak varsa çalıştırılır. İşlevi onSaveInstanceState içinde çağırıyorum, böylece bayrağı (mEditing) EditText görünümünün bir durumu olarak ve önemli düğmeler tıklandığında ve etkinlik kapatıldığında kaydetmeme gerek kalmıyor.
TexWatcher'a dikkat edin çünkü sık sık çağrıdır, onRestoreInstanceState kodu metin girerken tepki vermemek için odak koşulunu kullanıyorum. ben
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();
}
}
TextView.OnEditorActionListener türü yerine kullanılabilecek bu soyut sınıf gibi bir şey yaptım.
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
}
EditText'te yazmayı bitirmek için basit
benim için çalıştı, java kullanıyorsanız onu dönüştürün
Kotlin'de
youredittext.doAfterTextChanged { searchTerm ->
val currentTextLength = searchTerm?.length
Handler().postDelayed({
if (currentTextLength == searchTerm?.length) {
// your code
Log.d("aftertextchange", "ON FINISH TRIGGER")
}
}, 3000)
}