android EditText-完成输入事件


121

我想在用户完成编辑EditText时捕获一个事件。

如何做呢?


1
@PadmaKumar最自然的方法是,如果焦点丢失在EditText上,则用户一定会完成,但是从经验来看,似乎并不是所有的android小部件都可以正确地吸引焦点(我在Spinners和Buttons上遇到了这些问题)-因此其他小部件可能不会失去焦点...
AgentKnopf 2012年

3
为什么这么大的平台让我们处理这种简单的功能?如果Google至少将这些主要功能添加到支持库中,则Google不会丢失任何内容
MBH

如果您知道要输入的字符串的确切长度,请在afterTextChanged中获取文本。例如:override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Shylendra Madda '18

2
我很想知道为什么在Android中如此困难,以至于我们(包括我自己)需要搜索并开始在线讨论以及包含10余行代码的许多不同解决方案。
nsandersen,

Answers:


119

用户完成编辑后,他/他将按DoneEnter

((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. 
        }
    }
);

50
你能确定吗?我有进入/进入下一个可编辑字段的习惯-我几乎从不按Enter /完成-从客户那里看到的内容,他们也没有...我在谈论的是Edittexts / Comboboxes等列表如果您只给用户一个“输入”字段并强迫他在进入其他字段之前先按一个按钮,那显然是另一
回事了

5
记住,您还必须为您的编辑文本设置android:singleLine =“ true”。由于 stackoverflow.com/questions/15901863/...
史蒂芬·史密斯

1
好的解决方案,但可能会因null指针而崩溃...在完成操作时“ event”可以为null,因此event.isShiftPressed()会崩溃。如果使用此选项,则添加空指针检查。
Georgie

添加编辑以检查是否有空的“事件”。
Word重新排列

3
如果您按下关闭键盘的“返回”按钮怎么办?
user347187

183

更好的方法是,您还可以使用EditText onFocusChange侦听器来检查用户是否已完成编辑:(不需要依赖用户按下软键盘上的“完成”或“输入”按钮)

 ((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;
        }
      }
    }

60
如果只有一个可聚焦的话,这将无效EditText。它永远不会失去焦点。
巴特·

如果我们只有一个人,最好的方法是什么EditText?我必须使用onEditorAction吗?
Tux

3
如果只有一个EditText,则可以验证用户离开屏幕所做的一切。
克里斯汀

我试过了,但是没有用。每次按Enter键,都会给我类似的消息: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 }即使我键入了一些内容。这是一个仅接受数字的edittext。
ahitt6345 '16

1
有一个使用OnFocusChange侦听器的观点:如果EditText具有焦点并且设备旋转了,它将不会被调用!我通过将someOtherView.requestFocus()放在“活动onPause()”中来解决。(在super.onPause()之前)这样,EditText失去焦点并调用侦听器是安全的。
allofmex

60

我个人更喜欢输入结束后自动提交。这是您如何检测此事件的方法。

声明和初始化:

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);
            }
        }
    });

因此,更改文本后,计时器将开始等待下一次更改。当它们发生时,计时器被取消,然后再次启动。


11
这很棒,但请注意,计时器可能会导致内存泄漏,请Handler改用
Moh Mah 2015年

很好,坦斯克
VipPunkJoshers Droopy

什么是serviceConnector?
利他主义的

@altruistic这只是我的代码片段,可以从中提取答案。这是逻辑应该去的地方。
ZimaXXX '16

21

您可以使用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) {

        }
    };

27
恐怕这不是(完整的)解决方案-textWatcher在每次编辑后都会触发-如果您键入hello,则会在h,e,l,l和o时触发-它实际上不知道用户何时“完成” 。如果TextWatcher真正知道小部件何时失去焦点并且用户继续前进,
那就太好了

4

尽管许多答案的确指向正确的方向,但我认为它们都无法回答问题作者所想的内容。或者至少我对问题的理解有所不同,因为我正在寻找类似问题的答案。问题是“如何知道用户何时在没有按下按钮的情况下停止键入”,并触发一些操作(例如自动完成)。如果要执行此操作,请在onTextChanged中启动计时器,并延迟一段时间,您会认为用户已停止键入(例如500-700ms),对于启动计时器时的每个新字母,请取消较早的字母(或至少使用某种形式的标记当他们打勾时他们什么都不做)。这是我使用过的类似代码:

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

请注意,我在异步任务中修改了正在运行的boolean标志(任务从服务器获取json以自动完成)。

还请记住,这会创建许多计时器任务(我认为它们是在同一个线程上调度的,但是必须检查一下),因此可能有很多地方需要改进,但是这种方法也有效,最重要的是您应该使用计时器,因为没有“用户停止键入事件”


能否请您提供更多信息和示例代码?
约翰·欧内斯特·瓜达卢佩

代码的要旨在答案中,有关更多详细示例,请参见同一页面上使用相同方法的ZimaXXX的答案。我不知道我还能添加什么信息,如果您可以指定不清楚的地方,我会尝试添加详细信息。
伊戈尔·科尔达什(IgorČordaš)

4

如果您想在操作后隐藏键盘,则@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
        }
    }
});

3

一种不同的方法...这里是一个示例:如果用户在键入时有600-1000ms的延迟,您可能会认为他已停止。

 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();
                }
            }
        });


2

好的,这肯定会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;
                        }
                    }
            }
        });

1
多个文本编辑呢?这些heightDiff > 100东西是可怕的恕我直言。
Bondax

没问题,一切正常。看看这个stackoverflow.com/questions/2150078/...
Krit的

2

我这样解决了这个问题。我用过科特林。

        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.
            }
        })

0

我遇到了同样的问题,并且不想依靠用户按“完成”或“ Enter”键。

我的第一个尝试是使用onFocusChange侦听器,但发生在默认情况下,我的EditText获得了焦点。当用户按下其他视图时,onFocusChange被触发,而用户没有为其分配焦点。

下一个解决方案为我完成了此操作,如果用户触摸了EditText,则会附加onFocusChange:

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问​​题。


您每次触摸事件发生时都将设置焦点更改侦听器,这将是每秒几下。不要这样做。
jsonfry

0

尝试在聊天应用程序上实现“立即输入”时,我遇到了同样的问题。尝试如下扩展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) { }

}


0

我以同样的问题结束了她的工作,无法将解决方案与onEditorAction或onFocusChange配合使用,并且不想尝试使用计时器。定时器由于所有线程而太危险了,可能令人不快,因为您不知道何时执行代码,因此它太不可预测了。

当用户不使用按钮离开时,onEditorAction不会捕获,如果您使用它,请注意KeyEvent可以为null。两端的焦点都不可靠,用户无需输入任何文本或选择字段即可获得焦点并离开,并且用户无需离开最后一个EditText字段。

我的解决方案使用onFocusChange和当用户开始编辑文本时设置的标志以及用于从上一个焦点视图获取文本的函数,该函数在需要时调用。

我只是清除所有文本字段上的焦点以欺骗假文本视图代码,仅当该字段具有焦点时才执行clearFocus代码。我在onSaveInstanceState中调用该函数,因此不必将标志(mEditing)保存为EditText视图的状态,以及单击重要按钮时和活动关闭时。

使用TexWatcher时要小心,因为它经常被调用,当onRestoreInstanceStateState代码输入文本时,我经常使用焦点条件以不响应。一世

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();
    }
}

0

我做了类似此类抽象类的操作,可以代替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
}

0

易于触发在EditText中完成键入

为我工作,如果您使用java将其转换

在科特林

youredittext.doAfterTextChanged { searchTerm ->
val currentTextLength = searchTerm?.length
    Handler().postDelayed({
        if (currentTextLength == searchTerm?.length) {
            // your code 
           Log.d("aftertextchange", "ON FINISH TRIGGER")
          }
       }, 3000)
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.