Quero capturar um evento quando o usuário terminar de editar o EditText.
Como pode ser feito?
override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Quero capturar um evento quando o usuário terminar de editar o EditText.
Como pode ser feito?
override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Respostas:
Quando o usuário terminar a edição, ele / ela irá pressionar Done
ouEnter
((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.
}
}
);
Melhor forma, você também pode usar o ouvinte EditText onFocusChange para verificar se o usuário fez a edição: (não é necessário que o usuário pressione o botão Concluído ou Enter no teclado virtual)
((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
}
}
});
Nota: Para mais de um EditText, você também pode deixar sua classe implementar, em View.OnFocusChangeListener
seguida, definir os ouvintes para cada um de vocês EditText e validá-los conforme abaixo
((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
. Nunca perderá o foco.
EditText
? Eu tenho que usar onEditorAction
?
EditText
, você valida tudo o que o usuário fizer para sair da tela.
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 }
recebia uma mensagem semelhante a esta: Mesmo que eu tenha digitado algo. Este é um texto de edição que aceita apenas números.
Eu pessoalmente prefiro o envio automático após o fim da digitação. Veja como você pode detectar este evento.
Declarações e inicialização:
private Timer timer = new Timer();
private final long DELAY = 1000; // in ms
Ouvinte em, por exemplo, 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);
}
}
});
Portanto, quando o texto é alterado, o cronômetro começa a aguardar as próximas alterações. Quando eles ocorrem, o temporizador é cancelado e reiniciado.
Handler
em vez
Você pode fazer isso usando setOnKeyListener ou usando um textWatcher como:
Definir observador de texto editText.addTextChangedListener(textWatcher);
então ligue
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) {
}
};
Embora muitas respostas apontem na direção certa, acho que nenhuma delas responde o que o autor da pergunta estava pensando. Ou pelo menos entendi a pergunta de forma diferente porque estava procurando uma resposta para um problema semelhante. O problema é "Como saber quando o usuário para de digitar sem que ele pressione um botão" e acionar alguma ação (por exemplo, completar automaticamente). Se você quiser fazer isso, inicie o cronômetro em onTextChanged com um atraso que você consideraria que o usuário parou de digitar (por exemplo, 500-700ms), para cada nova letra ao iniciar o cronômetro cancele a anterior (ou pelo menos use algum tipo de sinalizar que, quando marcam, não fazem nada). Aqui está um código semelhante ao que usei:
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if (!running) {
new DoPost().execute(s.toString());
});
}
}, 700);
Observe que eu modifico o sinalizador booleano em execução dentro da minha tarefa assíncrona (a tarefa obtém o json do servidor para preenchimento automático).
Também tenha em mente que isso cria muitas tarefas temporizadas (acho que elas estão agendadas no mesmo Tópico, mas você teria que verificar isso), então provavelmente há muitos lugares para melhorar, mas essa abordagem também funciona e o resultado final é que você deve use um cronômetro, pois não há nenhum "evento de usuário parou de digitar"
@Reno e @Vinayak B respondem juntos se você quiser ocultar o teclado após a ação
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
}
}
});
Uma abordagem diferente ... aqui está um exemplo: Se o usuário tem um atraso de 600-1000ms quando está digitando, você pode considerar que ele está parado.
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();
}
}
});
Ok, isso vai funcionar 100% com certeza.
Primeiro, você precisará configurar o ouvinte se o teclado for mostrar ou ocultar. Se o teclado estiver aparecendo, provavelmente o usuário está digitando, caso contrário, termine de digitar.
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
material é assustador imho.
Eu resolvi esse problema dessa forma. Eu usei o 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.
}
})
Eu tive o mesmo problema e não queria contar com o usuário pressionando Concluído ou Enter.
Minha primeira tentativa foi usar o ouvinte onFocusChange, mas ocorreu que meu EditText obteve o foco por padrão. Quando o usuário pressionou alguma outra visualização, o onFocusChange foi acionado sem que o usuário nunca tivesse atribuído o foco.
A próxima solução fez isso para mim, em que onFocusChange é anexado se o usuário tocou em 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
}
}
}
}
}
No meu caso, quando o usuário terminou a edição, a tela foi renderizada novamente, renovando assim o objeto myEditText. Se o mesmo objeto for mantido, você provavelmente deve remover o ouvinte onFocusChange em onFocusChange para evitar o problema de onFocusChange descrito no início desta postagem.
Eu tive o mesmo problema ao tentar implementar 'agora digitando' no aplicativo de bate-papo. tente estender EditText da seguinte maneira:
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) { }
}
Eu terminei ela com o mesmo problema e não consegui usar a solução com onEditorAction ou onFocusChange e não queria tentar o cronômetro. Um cronômetro é muito perigoso para gosto, por causa de todos os threads e muito imprevisível, já que você não sabe quando seu código é executado.
O onEditorAction não detecta quando o usuário sai sem usar um botão e, se você usá-lo, observe que KeyEvent pode ser nulo. O foco não é confiável em ambas as extremidades, o usuário pode obter o foco e sair sem inserir nenhum texto ou selecionar o campo e o usuário não precisa sair do último campo EditText.
Minha solução usa onFocusChange e um sinalizador definido quando o usuário começa a editar o texto e uma função para obter o texto da última visualização em foco, que chamo quando necessário.
Eu apenas limpo o foco em todos os meus campos de texto para enganar o código de exibição de texto de saída. O código clearFocus só é executado se o campo tiver foco. Eu chamo a função em onSaveInstanceState para que não precise salvar o sinalizador (mEditing) como um estado da visualização EditText e quando botões importantes são clicados e quando a atividade é fechada.
Tenha cuidado com o TexWatcher, pois ele é chamado frequentemente. Eu uso a condição em foco para não reagir quando o código onRestoreInstanceState insere texto. Eu
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();
}
}
Eu fiz algo como esta classe abstrata que pode ser usada no lugar do tipo 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
}
Simples de acionar, terminar de digitar em EditText
funcionou para mim, se você estiver usando java, convertê-lo
Em Kotlin
youredittext.doAfterTextChanged { searchTerm ->
val currentTextLength = searchTerm?.length
Handler().postDelayed({
if (currentTextLength == searchTerm?.length) {
// your code
Log.d("aftertextchange", "ON FINISH TRIGGER")
}
}, 3000)
}