Tôi muốn bắt một sự kiện khi người dùng hoàn thành chỉnh sửa EditText.
Nó được hoàn thiện bằng cách nào?
override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Tôi muốn bắt một sự kiện khi người dùng hoàn thành chỉnh sửa EditText.
Nó được hoàn thiện bằng cách nào?
override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Câu trả lời:
Khi người dùng chỉnh sửa xong, họ sẽ nhấn Done
hoặcEnter
((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.
}
}
);
Cách tốt hơn, bạn cũng có thể sử dụng trình nghe EditText onF FocusChange để kiểm tra xem người dùng đã chỉnh sửa xong chưa (Không cần phụ thuộc vào người dùng nhấn nút Xong hoặc Enter trên bàn phím Mềm)
((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
}
}
});
Lưu ý: Đối với nhiều hơn một EditText, bạn cũng có thể để lớp của mình triển khai View.OnFocusChangeListener
sau đó đặt các trình nghe cho từng bạn EditText và xác thực chúng như dưới đây
((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
. Nó sẽ không bao giờ mất tập trung.
EditText
? Tôi có phải sử dụng onEditorAction
không?
EditText
, bạn xác nhận bất cứ điều gì người dùng làm để rời khỏi màn hình.
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 }
Mặc dù tôi đã gõ một cái gì đó. Đây là một edittext chỉ chấp nhận số.
Cá nhân tôi thích tự động gửi sau khi kết thúc gõ. Đây là cách bạn có thể phát hiện sự kiện này.
Tuyên bố và khởi tạo:
private Timer timer = new Timer();
private final long DELAY = 1000; // in ms
Trình nghe trong ví dụ 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);
}
}
});
Vì vậy, khi văn bản được thay đổi, bộ đếm thời gian bắt đầu chờ đợi bất kỳ thay đổi tiếp theo nào xảy ra. Khi chúng xảy ra hẹn giờ bị hủy và sau đó bắt đầu lại.
Handler
thay vào đó
Bạn có thể làm điều đó bằng cách sử dụng setOnKeyListener hoặc sử dụng trình xem văn bản như:
Đặt trình xem văn bản editText.addTextChangedListener(textWatcher);
sau đó gọi
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) {
}
};
Mặc dù nhiều câu trả lời đi đúng hướng nhưng tôi nghĩ không ai trong số họ trả lời được tác giả của câu hỏi đang nghĩ gì. Hoặc ít nhất tôi đã hiểu câu hỏi khác đi vì tôi đang tìm câu trả lời cho vấn đề tương tự. Vấn đề là "Làm thế nào để biết khi nào người dùng dừng gõ mà không cần nhấn nút" và kích hoạt một số hành động (ví dụ: tự động hoàn thành). Nếu bạn muốn thực hiện việc này, hãy khởi động Bộ định thời trong onText Thay đổi độ trễ mà bạn sẽ xem xét người dùng đã dừng nhập (ví dụ 500-700ms), cho mỗi chữ cái mới khi bạn khởi động bộ định thời hủy bỏ cái trước đó (hoặc ít nhất là sử dụng một số loại gắn cờ rằng khi họ đánh dấu họ không làm gì cả). Đây là mã tương tự với những gì tôi đã sử dụng:
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if (!running) {
new DoPost().execute(s.toString());
});
}
}, 700);
Lưu ý rằng tôi sửa đổi cờ boolean đang chạy bên trong tác vụ không đồng bộ của mình (Tác vụ lấy json từ máy chủ để tự động hoàn thành).
Ngoài ra, hãy nhớ rằng điều này tạo ra nhiều tác vụ hẹn giờ (tôi nghĩ rằng chúng được lên lịch trên cùng một Chủ đề nhưng sẽ phải kiểm tra điều này), vì vậy có thể có nhiều nơi để cải thiện nhưng cách tiếp cận này cũng hoạt động và điểm mấu chốt là bạn nên sử dụng Timer vì không có "Sự kiện người dùng dừng gõ"
cả @Reno và @Vinayak B trả lời cùng nhau nếu bạn muốn ẩn bàn phím sau khi hành động
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
}
}
});
Một cách tiếp cận khác ... đây là một ví dụ: Nếu người dùng có độ trễ 600-1000ms khi đang gõ, bạn có thể cân nhắc rằng mình đã dừng.
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();
}
}
});
Được rồi, điều này sẽ làm việc 100% chắc chắn.
Trước tiên, bạn sẽ cần thiết lập trình nghe nếu bàn phím hiển thị hoặc ẩn. Nếu bàn phím hiển thị thì có lẽ người dùng đang gõ, nếu không thì gõ xong.
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
thứ đáng sợ imho.
Tôi đã giải quyết vấn đề này theo cách này. Tôi đã sử dụng 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.
}
})
Tôi gặp vấn đề tương tự và không muốn dựa vào người dùng nhấn Xong hoặc Enter.
Nỗ lực đầu tiên của tôi là sử dụng trình nghe onF FocusChange, nhưng theo mặc định, EditText của tôi đã lấy nét theo mặc định. Khi người dùng nhấn một số chế độ xem khác, onF FocusChange đã được kích hoạt mà không bao giờ người dùng đã gán cho nó tiêu điểm.
Giải pháp tiếp theo đã làm điều đó cho tôi, nơi gắn onF FocusChange nếu người dùng chạm vào 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
}
}
}
}
}
Trong trường hợp của tôi, khi người dùng chỉnh sửa xong, màn hình đã được đăng ký lại, do đó làm mới đối tượng myEditText. Nếu cùng một đối tượng được giữ, có lẽ bạn nên xóa trình nghe onF FocusChange trong onF FocusChange để ngăn sự cố onF FocusChange được mô tả ở đầu bài này.
Tôi gặp vấn đề tương tự khi cố gắng thực hiện 'bây giờ gõ' trên ứng dụng trò chuyện. cố gắng mở rộng EditText như sau:
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) { }
}
Tôi đã kết thúc cô ấy với cùng một vấn đề và tôi không thể sử dụng giải pháp với onEditorAction hoặc onF FocusChange và không muốn thử hẹn giờ. Một bộ đếm thời gian là quá nguy hiểm cho hương vị, bởi vì tất cả các luồng và quá khó đoán, vì bạn không biết khi nào mã của bạn được thực thi.
OnEditorAction không bắt được khi người dùng rời đi mà không sử dụng nút và nếu bạn sử dụng, vui lòng lưu ý rằng KeyEvent có thể là null. Trọng tâm không đáng tin cậy ở cả hai đầu, người dùng có thể lấy nét và rời khỏi mà không cần nhập bất kỳ văn bản nào hoặc chọn trường và người dùng không cần phải rời khỏi trường EditText cuối cùng.
Giải pháp của tôi sử dụng onF FocusChange và đặt cờ khi người dùng bắt đầu chỉnh sửa văn bản và chức năng để lấy văn bản từ chế độ xem tập trung cuối cùng mà tôi gọi khi cần.
Tôi chỉ xóa tiêu điểm trên tất cả các trường văn bản của mình để đánh lừa mã xem văn bản rời, Mã ClearF Focus chỉ được thực thi nếu trường có tiêu điểm. Tôi gọi hàm trong onSaveInstanceState để tôi không phải lưu cờ (mEditing) dưới dạng trạng thái của chế độ xem Chỉnh sửa và khi các nút quan trọng được nhấp và khi đóng hoạt động.
Hãy cẩn thận với TexWatcher vì đây là cuộc gọi thường xuyên. Tôi sử dụng điều kiện tập trung để không phản ứng khi mã onRestoreInstanceState nhập văn bản. Tôi
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();
}
}
Tôi đã làm một cái gì đó giống như lớp trừu tượng này có thể được sử dụng thay cho kiểu 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
}
Đơn giản để kích hoạt kết thúc gõ trong EditText
làm việc cho tôi, nếu bạn sử dụng java chuyển đổi nó
Ở Kotlin
youredittext.doAfterTextChanged { searchTerm ->
val currentTextLength = searchTerm?.length
Handler().postDelayed({
if (currentTextLength == searchTerm?.length) {
// your code
Log.d("aftertextchange", "ON FINISH TRIGGER")
}
}, 3000)
}