사용자가 소프트 키보드를 닫았을 때 감지


114

내보기에 EditText 위젯이 있습니다. 사용자가 EditText 위젯을 선택하면 몇 가지 지침이 표시되고 소프트 키보드가 나타납니다.

OnEditorActionListener를 사용하여 사용자가 텍스트 입력을 완료 한시기를 감지하고 키보드를 닫고 지침을 숨기고 몇 가지 작업을 수행합니다.

내 문제는 사용자가 BACK 키를 눌러 키보드를 닫을 때입니다. OS가 키보드를 닫지 만 내 지침 (숨겨야 함)은 여전히 ​​표시됩니다.

OnKeyDown 재정의를 시도했지만 BACK 버튼을 사용하여 키보드를 닫을 때 호출되지 않는 것 같습니다.

EditText 위젯에서 OnKeyListener를 설정하려고 시도했지만 호출되지 않는 것 같습니다.

소프트 키보드가 해제되는시기를 어떻게 감지 할 수 있습니까?

답변:


160

나는 이것을하는 방법을 알고있다. EditText를 하위 클래스로 만들고 다음을 구현합니다.

@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
  if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
    // Do your thing.
    return true;  // So it is not propagated.
  }
  return super.dispatchKeyEvent(event);
}

다음은 사용자 정의보기를 사용하는 방법에 대한 링크입니다 (EditText를 하위 클래스로 지정하는 경우) : http://developer.android.com/guide/topics/ui/custom-components.html


2
하드웨어 키보드를 사용하는 Android 사용자로부터이 작업을 수행하면 키 누름을 방해한다는보고를 받고 있습니다. 현재 추가 정보가 없습니다.
esilver 2011

나는 몇 가지 해결책을 찾고 있었는데 이것이 지금까지 최고입니다!
Friesgaard 2014 년

10
잠깐 기다려 잠깐, 나는 이것을 세 번째로 봤다-슈퍼 콜이 있어야하지 onKeyPreIme않습니까? 아니면 그렇게되지 않는 특별한 이유가 있습니까?
Erhannis 2014

EditText를 서브 클래 싱 할 수없는 경우 (예 : SearchView에서)를 제외하고는 유용합니다. 키보드를 닫을 때 비어 있으면 SearchView를 숨기려고 할 때 발생하는 문제입니다. 왜 안드로이드 사람들이 이런 종류의 멋진 OSK API를 제공하지 않는지 궁금합니다.
tbm

2
비슷한 효과를 달성하기 위해 @tbm SearchView, 참조하시기 바랍니다 stackoverflow.com/questions/9629313/...
Cheok 연의 쳉

124

제이, 당신의 해결책은 좋습니다! 감사 :)

public class EditTextBackEvent extends EditText {

    private EditTextImeBackListener mOnImeBack;

    public EditTextBackEvent(Context context) {
        super(context);
    }

    public EditTextBackEvent(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public EditTextBackEvent(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && 
            event.getAction() == KeyEvent.ACTION_UP) {
            if (mOnImeBack != null) 
                mOnImeBack.onImeBack(this, this.getText().toString());
        }
        return super.dispatchKeyEvent(event);
    }

    public void setOnEditTextImeBackListener(EditTextImeBackListener listener) {
        mOnImeBack = listener;
    }

}

public interface EditTextImeBackListener {
    public abstract void onImeBack(EditTextBackEvent ctrl, String text);
}

우리가 감지하고 싶은 특별한 이유가 KeyEvent.ACTION_UP있습니까?
Cheok 연의 쳉

2
@CheokYanCheng 버튼을 눌렀을 때가 아니라 버튼에서 손을 뗄 때 사용자 동작이 정상적으로 적용되기 때문입니다.
jayeffkay 2015-08-17

3
android.support.v7.widget.AppCompatEditText착색 을 위해 연장하십시오 .
Sanvywell

확장 : AppCompatEditTextandroidx 용
COYG

큰! 솔루션을 생성하기위한 개선 만 제안합니다. 나는 onKeyPreIme의 인수를 "있는 그대로"리스너에게 전달합니다. 이렇게하면 필요한 곳에 다른 방식으로 논리를 구현할 수 있습니다.
marcRDZ

17

super.onKeyPreIme ()를 호출하여 Jay의 솔루션을 약간 변경했습니다.

_e = new EditText(inflater.getContext()) {
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK){
            cancelTextInput();
        }
        return super.onKeyPreIme(keyCode, event);
    }
};

멋진 솔루션, Jay, +1!


14

다음은 키보드가 표시되는지 여부를 감지하는 사용자 정의 EditText입니다.

/**
 * Created by TheFinestArtist on 9/24/15.
 */
public class KeyboardEditText extends EditText {

    public KeyboardEditText(Context context) {
        super(context);
    }

    public KeyboardEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public KeyboardEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        if (listener != null)
            listener.onStateChanged(this, true);
    }

    @Override
    public boolean onKeyPreIme(int keyCode, @NonNull KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
                && event.getAction() == KeyEvent.ACTION_UP) {
            if (listener != null)
                listener.onStateChanged(this, false);
        }
        return super.onKeyPreIme(keyCode, event);
    }

    /**
     * Keyboard Listener
     */
    KeyboardListener listener;

    public void setOnKeyboardListener(KeyboardListener listener) {
        this.listener = listener;
    }

    public interface KeyboardListener {
        void onStateChanged(KeyboardEditText keyboardEditText, boolean showing);
    }
}

8

이제 2019 년 ...
그래서 Kotlin으로 더 깔끔한 솔루션을 만들었습니다

1. 확장 기능을 만듭니다.

fun Activity.addKeyboardToggleListener(onKeyboardToggleAction: (shown: Boolean) -> Unit): KeyboardToggleListener? {
    val root = findViewById<View>(android.R.id.content)
    val listener = KeyboardToggleListener(root, onKeyboardToggleAction)
    return root?.viewTreeObserver?.run {
        addOnGlobalLayoutListener(listener)
        listener
    }
}

2. 토글 리스너는 다음과 같습니다.

open class KeyboardToggleListener(
        private val root: View?,
        private val onKeyboardToggleAction: (shown: Boolean) -> Unit
) : ViewTreeObserver.OnGlobalLayoutListener {
    private var shown = false
    override fun onGlobalLayout() {
        root?.run {
            val heightDiff = rootView.height - height
            val keyboardShown = heightDiff > dpToPx(200f)
            if (shown != keyboardShown) {
                onKeyboardToggleAction.invoke(keyboardShown)
                shown = keyboardShown
            }
        }
    }
}

fun View.dpToPx(dp: Float) = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics).roundToInt()

3. 다음과 같이 간단한 활동에서 사용하십시오 .

addKeyboardToggleListener {shown ->
          // hurray! Now you know when the keyboard is shown and hidden!!
      }

Kotlin 솔루션에 감사드립니다. 구현했을 때 하나의 키보드 변경과 시작시 리스너를 여러 번 실행한다는 것을 알았습니다. open / not open 상태를 저장하고 값이 실제로 다를 때만 리스너를 호출해야했습니다.
RandomEngy

@RandomEngy는 KeyboardToggleListener에서 수정했습니다.
알려

4

Edittext를 확장하는 클래스를 만들고 코드에서 해당 edittext를 사용하기 만하면됩니다. 사용자 정의 edittext에서 다음 메서드를 재정의하면됩니다.

@Override
 public boolean onKeyPreIme(int keyCode, KeyEvent event) {
 if (keyCode == KeyEvent.KEYCODE_BACK) {

    //Here it catch all back keys
    //Now you can do what you want.

} else if (keyCode == KeyEvent.KEYCODE_MENU) {
    // Eat the event
    return true;
}
return false;}

키보드가 열릴 때 감지하는 방법이 있습니까?
powder366

3

다음은 키 리스너를 사용한 솔루션입니다. 왜 이것이 작동하는지 모르겠지만 사용자 정의 EditText에서 onKeyPreIme을 순수하게 재정의하면 OnKeyListener가 작동합니다.

SomeClass.java

customEditText.setOnKeyListener((v, keyCode, event) -> {
            if(event.getAction() == KeyEvent.ACTION_DOWN) {
                switch (keyCode) {
                    case KeyEvent.KEYCODE_BACK:
                        getPresenter().onBackPressed();
                        break;
                }
            }
            return false;
        }); 

CustomEditText.java

@Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        return super.dispatchKeyEvent(event);
    }

3

@olivier_sdg의 답변을 사용하지만 Kotlin으로 변환 :

class KeyboardEditText : AppCompatEditText {

    var listener: Listener? = null
  
    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
  
    override fun onKeyPreIme(keyCode: Int, event: KeyEvent): Boolean {
        if (event.keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
            listener?.onImeBack(this)
        }
        return super.dispatchKeyEvent(event)
    }
  
    interface Listener {
        fun onImeBack(editText: KeyboardEditText)
    }

}

용법:

keyboardEditText.listener = object : KeyboardEditText.Listener {
    override fun onImeBack(editText: KeyboardEditText) {
        //Back detected
    }
}

2

Xamarin에서 동일한 작업을 수행하려는 모든 사용자를 위해 약간 다른 몇 가지 주요 답변을 번역했습니다. 여기 에 요점을 만들었지 만 요약하면 사용자 정의 EditText를 만들고 다음과 OnKeyPreIme같이 재정의합니다 .

public class CustomEditText : EditText
{
    public event EventHandler BackPressed;

    // ...

    public override bool OnKeyPreIme([GeneratedEnum] Keycode keyCode, KeyEvent e)
    {
        if (e.KeyCode == Keycode.Back && e.Action == KeyEventActions.Up)
        {
            BackPressed?.Invoke(this, new EventArgs());
        }

        return base.OnKeyPreIme(keyCode, e);
    }
}

... 그리고 뷰에서 ...

editText = FindViewById<CustomEditText>(Resource.Id.MyEditText);
editText.BackPressed += (s, e) => 
{
    // <insert code here>
};

단순한 예제 일 뿐이지 만 이벤트 처리기에서 익명 메서드를 사용하지 않는 것이 좋습니다. 메모리 누수가 발생하고 많은 사람들이 여기에있는 예제를 사용하고이를 깨닫지 못한 채 실행합니다. 출처 : docs.microsoft.com/en-us/xamarin/cross-platform/deploy-test/…
Jared

0

hideSoftInputFromWindow 키보드가 닫히면 true를 반환합니다. 값을 사용하여 Android에서 키보드 닫기를 감지합니다.

InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);

        if (imm.hideSoftInputFromWindow(findFocus().getWindowToken(),
                InputMethodManager.HIDE_NOT_ALWAYS)) {
            //keyboard is closed now do what you need here
        }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.