android EditText-입력 완료 이벤트


122

사용자가 EditText 편집을 마치면 이벤트를 포착하고 싶습니다.

어떻게 할 수 있습니까?


1
@PadmaKumar 가장 자연스러운 방법은 EditText에서 포커스를 잃어버린 경우입니다. 사용자가 가장 확실하게 완료되었지만 경험상 모든 Android 위젯이 포커스를 제대로 잡는 것은 아닌 것 같습니다 (스피너 및 버튼에 문제가 있음). 그래서 다른 위젯하지 잃게 초점 ... 수도
AgentKnopf

3
왜 그렇게 큰 플랫폼이 이런 종류의 간단한 기능을 다룰 수 있는가? Google은 최소한 지원 라이브러리에 이러한 주요 기능을 추가해도 잃지 않을 것입니다
MBH

사용자가 입력 할 문자열의 정확한 길이를 알고 있다면 afterTextChanged에서 텍스트를 가져옵니다. 예 :override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Shylendra Madda

2
Android에서 이것이 왜 그렇게 어려운지 궁금해서 머리를 긁적이며 10 줄 이상의 코드로 온라인 토론과 다양한 솔루션을 검색하고 시작해야합니다 ..?
nsandersen

답변:


118

사용자가 편집을 마치면 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. 
        }
    }
);

50
그것에 대해 확신 할 수 있습니까? 나는 다음 편집 가능한 필드를 두드리는 습관이 있습니다.-저는 Enter / Done을 ​​거의 누르지 않습니다. 그리고 고객으로부터 본 것, 그들도 마찬가지입니다. . 그 다음 다른 분야에 진출하기 전에 당신은 단지 사용자가 하나의 입력 필드를 제공하고, 버튼을 눌러 그를 강제로하면 분명히의 다른 이야기 ... 그
AgentKnopf

5
또한 편집 텍스트에 대해 android : singleLine = "true"를 설정해야합니다. 감사합니다 stackoverflow.com/questions/15901863/...
스티븐 스미스에게

1
좋은 해결책이지만 null 포인터로 충돌 할 수 있습니다 ... 'event'는 Done 작업에서 null이 될 수 있으므로 event.isShiftPressed ()가 충돌합니다. 이것을 사용하면 널 포인터 검사를 추가하십시오.
Georgie

null "이벤트"를 확인하기 위해 편집이 추가되었습니다.
Word

3
키보드를 닫는 BACK 버튼을 누르면 어떨까요?
user347187 19-09-04

183

더 좋은 방법은 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;
        }
      }
    }

60
focusable이 하나만있는 경우 작동하지 않습니다 EditText. 초점을 잃지 않을 것입니다.
Bart Friederichs

우리가 하나만 가지고 있다면 가장 좋은 방법은 무엇입니까 EditText? 사용해야 onEditorAction합니까?
Tux 2015

3
하나만있는 경우 EditText사용자가 화면에서 나가기 위해 수행하는 작업에 대해 유효성을 검사합니다.
Christine

나는 이것을 시도했지만 작동하지 않았습니다. 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 }됩니다. 입력 한 내용이 있어도 숫자 만 허용하는 편집 텍스트입니다.
ahitt6345

1
OnFocusChange 리스너를 사용하는 측면이 있습니다. EditText에 포커스가 있고 장치가 회전하면 호출되지 않습니다! 활동 onPause ()에 someOtherView.requestFocus ()를 넣어 해결했습니다. (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대신에
모스 마작을

대단해, 탄 스크.
VipPunkJoshers Droopy

serviceConnector 란 무엇입니까?
이타적인

@altruistic 답을 내놓은 코드의 일부일뿐입니다. 논리가 가야 할 곳입니다.
ZimaXXX

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 실제로 알고한다면 좋을 것
AgentKnopf

4

많은 답변이 올바른 방향을 가리키고 있지만 질문 작성자가 생각한 것에 대한 답변은 아무도 없다고 생각합니다. 또는 적어도 비슷한 문제에 대한 답을 찾고 있었기 때문에 질문을 다르게 이해했습니다. 문제는 "사용자가 버튼을 누르지 않고 입력을 중지하는 경우를 아는 방법"이고 일부 작업 (예 : 자동 완성)을 트리거하는 것입니다. 이 작업을 수행하려면 사용자가 입력을 중지 한 것으로 간주 할 수있는 지연 시간 (예 : 500-700ms)을 사용하여 onTextChanged에서 타이머를 시작하고, 타이머를 시작할 때 새 문자마다 이전 문자를 취소하거나 적어도 체크 표시를하면 아무것도하지 않습니다.) 다음은 내가 사용한 것과 유사한 코드입니다.

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

비동기 작업 내에서 실행중인 부울 플래그를 수정합니다 (작업은 자동 완성을 위해 서버에서 json을 가져옴).

또한 이것은 많은 타이머 작업을 생성한다는 것을 명심하십시오 (나는 그들이 동일한 스레드에 예약되어 있다고 생각하지만 이것을 확인해야 할 것입니다), 아마도 개선해야 할 곳이 많지만이 접근 방식도 작동하고 결론은 당신이해야한다는 것입니다 "사용자가 입력 중지 이벤트"가 없으므로 타이머를 사용합니다.


이에 대한 자세한 정보와 샘플 코드를 제공해 주시겠습니까?
John Ernest Guadalupe

코드의 요지는 대답에 있습니다. 자세한 예는 동일한 접근 방식을 사용하는 동일한 페이지에서 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물건은 무서운 imho입니다.
Bondax

문제 없습니다. 잘 작동합니다. 이 stackoverflow.com/questions/2150078/…을
Krit

2

이 문제를 이렇게 해결했습니다. 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.
            }
        })

0

나는 같은 문제가 있었고 Done 또는 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 리스너를 제거해야합니다.


터치 이벤트가 발생할 때마다 포커스 변경 리스너를 설정합니다. 이는 1 초에 몇 번입니다. 이러지 마세요.
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는 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();
    }
}

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를 사용하는 경우 변환하십시오.

Kotlin에서

youredittext.doAfterTextChanged { searchTerm ->
val currentTextLength = searchTerm?.length
    Handler().postDelayed({
        if (currentTextLength == searchTerm?.length) {
            // your code 
           Log.d("aftertextchange", "ON FINISH TRIGGER")
          }
       }, 3000)
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.