我有几个输入字段的活动。活动开始后,将显示软键盘。当按下后退按钮软键盘关闭并关闭活动时,我需要再按下一次后退按钮。
因此,问题是:是否可以拦截后退按钮以关闭软键盘并在不创建自定义功能的情况下按一下后退按钮来完成活动InputMethodService?
PS我知道在其他情况下如何拦截后退按钮:onKeyDown()或者,onBackPressed()但在这种情况下不起作用:只有第二次按下后退按钮才能被拦截。
我有几个输入字段的活动。活动开始后,将显示软键盘。当按下后退按钮软键盘关闭并关闭活动时,我需要再按下一次后退按钮。
因此,问题是:是否可以拦截后退按钮以关闭软键盘并在不创建自定义功能的情况下按一下后退按钮来完成活动InputMethodService?
PS我知道在其他情况下如何拦截后退按钮:onKeyDown()或者,onBackPressed()但在这种情况下不起作用:只有第二次按下后退按钮才能被拦截。
Answers:
是的,完全有可能显示和隐藏键盘并截获对后退按钮的呼叫。由于已经提到了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">
在活动中,我们设置输入字段并调用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()函数设置了输入字段。它还使Enter键能够执行功能(在我的情况下是搜索)。
@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);
}
无论如何,这是我对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);
}
}
不幸的是,我不能承担所有的功劳。如果您在Android来源中查找快速SearchDialog框,则会看到该创意的来源。
getContext()为即可简化代码Activity。只要布局的上下文是所讨论的活动,就可以了。但是我不知道是否不可能。
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;
}
在您的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);
}
}
我发现,重写Layout Class的dispatchKeyEventPreIme方法也很好。只需将您的主活动设置为属性并启动预定义的方法。
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);
}
}
<?xml version="1.0" encoding="utf-8"?> <view class="package.LinearLayoutGradient"...
我通过重写dispatchKeyEvent获得成功:
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
finish();
return true;
}
return super.dispatchKeyEvent(event);
}
隐藏键盘并完成活动。
您如何显示软键盘?
如果您使用InputMethodManager.showSoftInput(),则可以尝试传入ResultReceiver和实施onReceiveResult()以处理RESULT_HIDDEN
http://developer.android.com/reference/android/view/inputmethod/InputMethodManager.html
showSoftInput()我的手机和仿真器上没有显示键盘,所以我用了toggleSoftInput()
我有同样的问题,但是通过拦截后退键来解决它。就我而言(HTC Desire,Android 2.2,应用程序API级别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();
}
在您的BackPressed实现中尝试此代码(android中的Block Back Button):
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(myEditText.getWindowToken(), 0);
我建议您看看@关闭/隐藏Android软键盘
onBackPressed()无法正常工作。并且只有在第二次按下程序进入程序之后onBackPressed()。
我的@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)
}