从软键盘拦截后退按钮

Ser*_*tov 80 android

我有几个输入字段的活动.当活动开始时,显示软键盘.当按下后退按钮软键盘关闭并关闭活动时,我需要再次按下后退按钮.

所以问题是:是否有可能拦截后退按钮关闭软键盘并在一次按下后退按钮完成活动而不创建自定义InputMethodService

PS我知道如何在其他情况下拦截后退按钮:onKeyDown()或者onBackPressed()在这种情况下它不起作用:只有第二次按下后退按钮被拦截.

mhr*_*dek 76

是的,完全可以显示和隐藏键盘并拦截对后退按钮的调用.这是一个额外的努力,因为已经提到在API中没有直接的方法来做到这一点.关键是boolean dispatchKeyEventPreIme(KeyEvent)在布局中覆盖.我们做的是创建我们的布局.我选择了RelativeLayout,因为它是我的Activity的基础.

<?xml version="1.0" encoding="utf-8"?>
<com.michaelhradek.superapp.utilities.SearchLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.michaelhradek.superapp"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/white">
Run Code Online (Sandbox Code Playgroud)

在我们的Activity中,我们设置输入字段并调用该setActivity(...)函数.

private void initInputField() {
    mInputField = (EditText) findViewById(R.id.searchInput);        

    InputMethodManager imm = 
        (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 
    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 
            InputMethodManager.HIDE_IMPLICIT_ONLY);

    mInputField.setOnEditorActionListener(new OnEditorActionListener() {

        @Override
        public boolean onEditorAction(TextView v, int actionId,
                KeyEvent event) {
            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                performSearch();
                return true;
            }

            return false;
        }
    });

    // Let the layout know we are going to be overriding the back button
    SearchLayout.setSearchActivity(this);
}
Run Code Online (Sandbox Code Playgroud)

显然,该initInputField()函数设置输入字段.它还使enter键能够执行功能(在我的例子中是搜索).

@Override
public void onBackPressed() {
    // It's expensive, if running turn it off.
    DataHelper.cancelSearch();
    hideKeyboard();
    super.onBackPressed();
}
Run Code Online (Sandbox Code Playgroud)

因此,当onBackPressed()在我们的布局中调用时,我们可以做任何我们想做的事情,比如隐藏键盘:

private void hideKeyboard() {
    InputMethodManager imm = (InputMethodManager) 
        getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(mInputField.getWindowToken(), 0);
}
Run Code Online (Sandbox Code Playgroud)

无论如何,这是我对RelativeLayout的重写.

package com.michaelhradek.superapp.utilities;

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.RelativeLayout;

/**
 * The root element in the search bar layout. This is a custom view just to 
 * override the handling of the back button.
 * 
 */
public class SearchLayout extends RelativeLayout {

    private static final String TAG = "SearchLayout";

    private static Activity mSearchActivity;;

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

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

    public static void setSearchActivity(Activity searchActivity) {
        mSearchActivity = searchActivity;
    }

    /**
     * Overrides the handling of the back key to move back to the 
     * previous sources or dismiss the search dialog, instead of 
     * dismissing the input method.
     */
    @Override
    public boolean dispatchKeyEventPreIme(KeyEvent event) {
        Log.d(TAG, "dispatchKeyEventPreIme(" + event + ")");
        if (mSearchActivity != null && 
                    event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            KeyEvent.DispatcherState state = getKeyDispatcherState();
            if (state != null) {
                if (event.getAction() == KeyEvent.ACTION_DOWN
                        && event.getRepeatCount() == 0) {
                    state.startTracking(event, this);
                    return true;
                } else if (event.getAction() == KeyEvent.ACTION_UP
                        && !event.isCanceled() && state.isTracking(event)) {
                    mSearchActivity.onBackPressed();
                    return true;
                }
            }
        }

        return super.dispatchKeyEventPreIme(event);
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我无法承担所有的功劳.如果您在Android 源代码中查看快速SearchDialog框,您将看到该想法的来源.

  • 只需将`getContext()`转换为`Activity`即可简化代码.如果布局的上下文是当然有问题的活动.但我不知道是不是. (3认同)
  • static mSearchActivity - 一个问题闻起来不对劲.如果您在布局中有两个这样的怎么办?请改用非静态变量. (3认同)
  • 这非常有效,并且实施起来也不太困难(尽管看起来有些吓人)。 (2认同)

Ali*_*mel 71

onKeyDown()onBackPressed()不适用于这种情况.你必须使用onKeyPreIme.

最初,您必须创建扩展EditText的自定义编辑文本.然后你必须实现控制KeyEvent.KEYCODE_BACK的 onKeyPreIme方法.在此之后,一个足以解决您的问题.这个解决方案非常适合我.

CustomEditText.java

public class CustomEditText extends EditText {

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

    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            // User has pressed Back key. So hide the keyboard
            InputMethodManager mgr = (InputMethodManager)         

           getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            mgr.hideSoftInputFromWindow(this.getWindowToken(), 0);
            // TODO: Hide your view as you do it in your activity
        }
        return false;
}
Run Code Online (Sandbox Code Playgroud)

在您的XML中

<com.YOURAPP.CustomEditText
     android:id="@+id/CEditText"
     android:layout_height="wrap_content"
     android:layout_width="match_parent"/> 
Run Code Online (Sandbox Code Playgroud)

在你的活动中

public class MainActivity extends Activity {
   private CustomEditText editText;

   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      editText = (CustomEditText) findViewById(R.id.CEditText);
   }
}
Run Code Online (Sandbox Code Playgroud)

  • 非常喜欢这个答案.将它与片段一起使用(在一个甚至不会总是显示的搜索栏中),并建议覆盖editText,这只会在必要时将此行为简单地封装起来 (4认同)
  • 请大家注意:为此添加一个快速界面可以让生活变得更好,幸运的是很容易做到 (2认同)

Kir*_*man 10

我发现,覆盖Layout类的dispatchKeyEventPreIme方法也很有效.只需将主Activity设置为属性并启动预定义方法即可.

public class LinearLayoutGradient extends LinearLayout {
    MainActivity a;

    public void setMainActivity(MainActivity a) {
        this.a = a;
    }

    @Override
    public boolean dispatchKeyEventPreIme(KeyEvent event) {
        if (a != null) {
            InputMethodManager imm = (InputMethodManager) a
                .getSystemService(Context.INPUT_METHOD_SERVICE);

            if (imm.isActive() && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                a.launchMethod;
            }
        }

        return super.dispatchKeyEventPreIme(event);
    }
}
Run Code Online (Sandbox Code Playgroud)


jas*_*der 7

我通过重写dispatchKeyEvent取得了成功:

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        finish();
        return true;
    }
    return super.dispatchKeyEvent(event);
}
Run Code Online (Sandbox Code Playgroud)

它隐藏键盘并完成活动.

  • 不适用于三星音符2.软键盘启动时不调用dispatchKeyEvent(). (5认同)