代码之家  ›  专栏  ›  技术社区  ›  Sergey Glotov Nitesh Khosla

从软键盘截取后退按钮

  •  75
  • Sergey Glotov Nitesh Khosla  · 技术社区  · 15 年前

    所以问题是:是否可以在不创建自定义项的情况下截取后退按钮以关闭软键盘并在一次按下后退按钮时完成活动 InputMethodService ?

    P、 我知道在其他情况下如何截取后退按钮: onKeyDown() onBackPressed()

    8 回复  |  直到 11 年前
        1
  •  76
  •   Aleks G    12 年前

    是的,完全可以显示和隐藏键盘并截获对后退按钮的调用。这是一个小的额外的努力,因为它已经提到,没有直接的方式来做这个在API中。关键是要超越 boolean dispatchKeyEventPreIme(KeyEvent) 在布局中。我们所做的是创建我们的布局。我选择相对主义,因为它是我活动的基础。

    <?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">
    

    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);
    }
    

    很明显 initInputField() 函数设置输入字段。它还允许回车键执行功能(在我的例子中是搜索)。

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

    所以当 onBackPressed()

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

    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);
        }
    }
    

    不幸的是我不能接受所有的功劳。如果你检查安卓系统 source for the quick SearchDialog box

        2
  •  77
  •   Alican Temel    8 年前

    onBackPressed() onKeyPreIme .

    最初,您必须创建扩展EditText的自定义编辑文本。然后你必须实现onkeypreme方法来控制 KeyEvent.KEYCODE返回

    自定义编辑文本.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;
    }
    

    在XML中

    <com.YOURAPP.CustomEditText
         android:id="@+id/CEditText"
         android:layout_height="wrap_content"
         android:layout_width="match_parent"/> 
    

    在你的活动中

    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);
       }
    }
    
        3
  •  10
  •   Kirill Rakhman    15 年前

    我发现 Layout类的方法也很有效。只需将主活动设置为属性并启动预定义的方法。

    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);
        }
    }
    
        4
  •  7
  •   jaseelder    14 年前

    dispatchKeyEvent事件 :

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

    它隐藏键盘并完成活动。

        5
  •  4
  •   superuser    15 年前

    如果你正在使用 InputMethodManager.showSoftInput() ,您可以尝试传入 ResultReceiver onReceiveResult() 处理 RESULT_HIDDEN

    http://developer.android.com/reference/android/view/inputmethod/InputMethodManager.html

        6
  •  2
  •   whlk    15 年前

    我也有同样的问题,但通过截取后面的按键来解决。在我的例子中(HTC Desire,Android 2.2,Application API Level 4),它关闭键盘并立即完成活动。不知道为什么这对你也不起作用:

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
    
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            onBackPressed();
            return true;
        }
        return super.onKeyUp(keyCode, event);
    }
    
    /**
     * Called when the activity has detected the user's press of the back key
     */
    private void onBackPressed() {
        Log.e(TAG, "back pressed");
        finish();
    }
    
        7
  •  1
  •   Brandon    14 年前

    使用 onKeyPreIme(int keyCode, KeyEvent event) KeyEvent.KEYCODE_BACK 事件。它非常简单,没有做任何花哨的编码。

        8
  •  0
  •   Community Mohan Dere    9 年前

    在背压实现中尝试此代码( Block Back Button in android ):

    InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(myEditText.getWindowToken(), 0);
    

    我建议你去看看@ Close/hide the Android Soft Keyboard

        9
  •  0
  •   tasjapr    6 年前

    我的@mhradek解决方案版本:

    class BazingaLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
        ConstraintLayout(context, attrs, defStyleAttr) {
    
    var activity: Activity? = null
    
    override fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
        activity?.let {
            if (event.keyCode == KeyEvent.KEYCODE_BACK) {
                val state = keyDispatcherState
                if (state != null) {
                    if (event.action == KeyEvent.ACTION_DOWN
                        && event.repeatCount == 0) {
                        state.startTracking(event, this)
                        return true
                    } else if (event.action == KeyEvent.ACTION_UP && !event.isCanceled && state.isTracking(event)) {
                        it.onBackPressed()
                        return true
                    }
                }
            }
        }
        return super.dispatchKeyEventPreIme(event)
    }
    

    xml文件

    <com... BazingaLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/grey">
     </com... BazingaLayout>
    

    碎片

        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            (view as BazingaLayout).activity = activity
            super.onViewCreated(view, savedInstanceState)
    }