Я хочу зафіксувати подію, коли користувач закінчує редагування EditText.
Як це можна зробити?
override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Я хочу зафіксувати подію, коли користувач закінчує редагування EditText.
Як це можна зробити?
override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Відповіді:
Після завершення редагування користувач натисне Done
або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.
}
}
);
Краще, ви також можете скористатися слухачем EditText onFocusChange, щоб перевірити, чи виконав редагування користувач: (Не потрібно покладатися на те, що користувач натисне кнопку "Готово" або "Enter" на м'якій клавіатурі)
((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
}
}
});
Примітка. Для більш ніж одного EditText ви також можете дозволити своєму класі реалізувати, View.OnFocusChangeListener
а потім встановити слухачів для кожного з вас EditText і перевірити їх, як показано нижче
((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
. Він ніколи не втратить уваги.
EditText
? Чи потрібно користуватися onEditorAction
?
EditText
, ви підтверджуєте, що користувач робить, щоб покинути екран.
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 }
Навіть якщо я щось набрав. Це редакційний текст, який приймає лише цифри.
Я особисто вважаю за краще автоматичне надсилання після закінчення набору тексту. Ось як можна виявити цю подію.
Декларації та ініціалізація:
private Timer timer = new Timer();
private final long DELAY = 1000; // in ms
Слухач у, наприклад, 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);
}
}
});
Отже, коли текст змінюється, таймер починає чекати наступних змін. Коли вони виникають, таймер скасовується і знову запускається.
Handler
натомість
Ви можете це зробити за допомогою setOnKeyListener або за допомогою textWatcher, наприклад:
Встановити спостерігач тексту editText.addTextChangedListener(textWatcher);
потім дзвоніть
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) {
}
};
Хоча багато відповідей вказують у правильному напрямку, я думаю, що жодна з них не відповідає тому, про що думав автор питання. Або принаймні я зрозумів питання по-іншому, тому що шукав відповіді на подібну проблему. Проблема полягає в тому, як "Як дізнатися, коли користувач перестає вводити текст, не натискаючи на нього кнопку", і запустити певну дію (наприклад, автоматичне завершення). Якщо ви хочете зробити це, запустіть Таймер в onTextChanged із запізненням, яке ви вважаєте, що користувач перестав вводити текст (наприклад, 500-700ms), для кожного нового листа, коли ви запустите таймер, скасуйте попередній (або принаймні використовуйте якийсь тип прапор, що коли вони галочують, вони нічого не роблять). Ось подібний код до того, що я використав:
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if (!running) {
new DoPost().execute(s.toString());
});
}
}, 700);
Зауважте, що я змінюю запущений булевий прапор всередині мого завдання async (Завдання отримує json від сервера для автоматичного завершення).
Також майте на увазі, що це створює багато завдань з таймером (я думаю, вони заплановані на одній темі, але вам доведеться це перевірити), тому, мабуть, є багато місць для вдосконалення, але такий підхід також працює, і суть полягає в тому, що вам слід використовувати таймер, оскільки немає "Користувач перестав вводити подію"
і Reno, і @Vinayak B відповідають разом, якщо ви хочете приховати клавіатуру після дії
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
}
}
});
Інший підхід ... ось приклад: Якщо у користувача затримка 600-1000 мс під час введення тексту, ви можете вважати, що він зупинений.
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();
}
}
});
Гаразд, це буде працювати на 100% точно.
Спочатку вам потрібно буде налаштувати слухача, якщо клавіатура відображається чи ховається. Якщо клавіатура відображається, то, ймовірно, користувач набирає текст, інакше робиться друк.
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
речі страшно імхо.
Я вирішив цю проблему таким чином. Я використовував котлін.
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.
}
})
У мене була така ж проблема, і я не хотів покладатися на те, що користувач натискає «Готово» або «Enter».
Моєю першою спробою було використання слухача onFocusChange, але сталося, що мій EditText отримав фокус за замовчуванням. Коли користувач натиснув якийсь інший вигляд, onFocusChange був запущений без того, щоб користувач ніколи присвоїв йому фокус.
Наступне рішення зробило це для мене, де onFocusChange додається, якщо користувач торкнувся 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
}
}
}
}
}
У моєму випадку, коли користувачем було виконано редагування екрана, було відтворено, тим самим оновивши об’єкт myEditText. Якщо зберігається той самий об’єкт, вам, ймовірно, слід видалити слухача onFocusChange в onFocusChange, щоб запобігти проблемі onFocusChange, описаній на початку цієї публікації.
У мене була така ж проблема, коли я намагався реалізувати додаток для чату. спробуйте розширити EditText так:
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) { }
}
Я закінчив її з тією ж проблемою, і я не міг використати рішення з onEditorAction або onFocusChange і не хотів спробувати таймер. Таймер занадто небезпечний для смаку, тому що він може використовуватись через всі потоки і занадто непередбачуваний, оскільки ви не знаєте, коли виконується код.
OnEditorAction не вловлює, коли користувач піде без використання кнопки, і якщо ви користуєтесь нею, будь ласка, зауважте, що KeyEvent може бути недійсним. Фокус недостовірний з обох кінців, користувач може отримати фокус і вийти, не вводячи жодного тексту чи вибираючи поле, і користувачеві не потрібно залишати останнє поле EditText.
Моє рішення використовує onFocusChange і встановити прапор, коли користувач починає редагувати текст і функцію для отримання тексту з останнього зосередженого перегляду, який я викликаю, коли потрібно.
Я просто очищую фокус на всіх моїх текстових полях, щоб обмацувати код подання тексту тексту, код clearFocus виконується лише у тому випадку, якщо поле має фокус. Я викликаю функцію в OnSaveInstanceState, тому мені не потрібно зберігати прапор (mEditing) як стан перегляду EditText і коли натискаються важливі кнопки та коли діяльність закрита.
Будьте обережні з TexWatcher, оскільки це часто дзвінок, я використовую умову фокусування, щоб не реагувати, коли код onRestoreInstanceState вводить текст. Я
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.
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
працював на мене, якщо ви використовуєте Java конвертувати його
У Котліні
youredittext.doAfterTextChanged { searchTerm ->
val currentTextLength = searchTerm?.length
Handler().postDelayed({
if (currentTextLength == searchTerm?.length) {
// your code
Log.d("aftertextchange", "ON FINISH TRIGGER")
}
}, 3000)
}