检测用户何时解除软键盘

deS*_*lby 109 android

我的视图中有一个EditText小部件.当用户选择EditText小部件时,我会显示一些指令并显示软键盘.

我使用OnEditorActionListener来检测用户何时完成文本输入,然后关闭键盘,隐藏指令并执行某些操作.

我的问题是当用户按下BACK键关闭键盘时.操作系统解除键盘,但我的指令(我需要隐藏)仍然可见.

我已经尝试重写OnKeyDown,但是当使用BACK按钮关闭键盘时,似乎没有调用.

我已经尝试在EditText小部件上设置OnKeyListener,但似乎也没有调用.

如何检测软键盘何时被解除?

小智 159

我知道这样做的方法.对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);
}
Run Code Online (Sandbox Code Playgroud)

以下是有关如何使用自定义视图的链接(当您将EditText子类化时):http: //developer.android.com/guide/topics/ui/custom-components.html

  • 等待等待,我只是第三次看这个 - 超级调用不应该是`onKeyPreIme`吗?或者有没有特别的理由不这样做? (10认同)
  • 我从使用硬件键盘的Android用户那里收到报告,认为这样做会以某种方式干扰按键。我目前没有任何其他信息。 (2认同)
  • @tbm要在`SearchView`中实现类似效果,请参阅http://stackoverflow.com/questions/9629313/auto-collapse-actionbar-searchview-on-soft-keyboard-close (2认同)

oli*_*sdg 121

周杰伦,你的解决方案很好!谢谢 :)

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);
}
Run Code Online (Sandbox Code Playgroud)

  • 确保扩展`android.support.v7.widget.AppCompatEditText`以进行着色. (3认同)
  • @CheokYanCheng这是因为用户操作通常在释放按钮时生效,而不是在开始按下时生效. (2认同)

Ste*_*ght 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);
    }
};
Run Code Online (Sandbox Code Playgroud)

精彩的解决方案,Jay,+ 1!


The*_*ist 13

这是我的自定义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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Leo*_*der 9

现在是 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
    }
}
Run Code Online (Sandbox Code Playgroud)

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()
Run Code Online (Sandbox Code Playgroud)

3.在任何活动中使用它就像这样简单

addKeyboardToggleListener {shown ->
          // hurray! Now you know when the keyboard is shown and hidden!!
      }
Run Code Online (Sandbox Code Playgroud)


bmj*_*hns 8

使用@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)
    }

}
Run Code Online (Sandbox Code Playgroud)

用法:

keyboardEditText.listener = object : KeyboardEditText.Listener {
    override fun onImeBack(editText: KeyboardEditText) {
        //Back detected
    }
}
Run Code Online (Sandbox Code Playgroud)


far*_*ran 5

只需创建一个扩展 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;}
Run Code Online (Sandbox Code Playgroud)