Ответ 1
Этот вопрос (без ответа еще и выглядя мрачным), кажется, задает тот же вопрос: Как проверить видимость программной клавиатуры на Android?
У меня есть вид виджетов EditText. Когда пользователь выбирает виджет EditText, я показываю некоторые инструкции и появляется мягкая клавиатура.
Я использую OnEditorActionListener для обнаружения, когда пользователь завершил ввод текста, и я увольняю клавиатуру, скрываю инструкции и выполняю некоторые действия.
Моя проблема в том, что пользователь отклоняет клавиатуру, нажимая клавишу BACK. ОС отклоняет клавиатуру, но мои инструкции (которые мне нужно скрыть) все еще видны.
Я попытался переопределить OnKeyDown, но это, похоже, не вызвано, когда кнопка BACK используется для отклонения клавиатуры.
Я попытался установить OnKeyListener на виджет EditText, но это, похоже, не вызвано.
Как определить, когда отклоняется мягкая клавиатура?
Этот вопрос (без ответа еще и выглядя мрачным), кажется, задает тот же вопрос: Как проверить видимость программной клавиатуры на Android?
Я знаю способ сделать это. Подкласс 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
Джей, ваше решение - это хорошо! спасибо:)
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);
}
Я немного изменил решение Jay, вызвав super.onKeyPreIme():
_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!
Вот мой пользовательский 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);
}
}
Просто создайте класс, который расширяет 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;}
Сейчас 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. Где слушатель переключения:
class KeyboardToggleListener(
private val root: View?,
private val onKeyboardToggleAction: (shown: Boolean) -> Unit
) : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
root?.run {
val heightDiff = rootView.height - height
val keyboardShown = heightDiff > dpToPx(200f)
onKeyboardToggleAction.invoke(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!!
}
Вот решение с ключевым слушателем. Я понятия не имею, почему это работает, но OnKeyListener работает, если вы просто переопределяете onKeyPreIme в своем пользовательском EditText.
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);
}
Используя ответ @olivier_sdg, но преобразованный в Kotlin:
class KeyboardEditText : EditText {
private var mOnImeBack: EditTextImeBackListener? = 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) {
if (mOnImeBack != null)
mOnImeBack!!.onImeBack(this, this.text.toString())
}
return super.dispatchKeyEvent(event)
}
fun setOnEditTextImeBackListener(listener: EditTextImeBackListener) {
mOnImeBack = listener
}
}
interface EditTextImeBackListener {
fun onImeBack(ctrl: KeyboardEditText, text: String)
}
Для тех, кто хочет сделать то же самое в 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>
};
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
}