我有一个包含两个活动的应用程序,有时,我需要切换活动,同时在刚恢复的活动的操作栏中打开搜索输入。一切正常,除了我无法拨动键盘。我的代码的相关位如下(注意:如果需要搜索输入,则由于切换活动而将布尔值startsearch设置为true
):
public class MyActivity extends Activity {
private InputMethodManager imm;
public boolean startsearch;
private MenuItem DestinationTxt;
private SearchView mySearchView;
@Override
protected void onCreate(Bundle savedInstanceState) {
// various initialisation, and then:
startsearch = false;
imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action_menu, menu);
DestinationTxt = menu.findItem(R.id.actionbar_search);
mySearchView = (SearchView)DestinationTxt.getActionView();
// more menu create stuff appears here
}
@Override
public void onResume() {
super.onResume();
if (startsearch) {
DestinationTxt.expandActionView();
imm.showSoftInput(mySearchView, 0);
}
}
}
并且action_menu.xml的相关位是
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/actionbar_search"
android:orderInCategory="1"
android:showAsAction="always|withText|collapseActionView"
android:actionViewClass="android.widget.SearchView"
android:icon="@drawable/earth_2508858_search_en"
android:inputType="textPostalAddress"
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"></item>
</menu>
正如我说的那样,这在大多数情况下都是可行的,因为在活动恢复时,操作栏搜索确实会获得焦点。但是,键盘没有出现,尽管(我从代码中可以看到)我已经明确要求了它。谁能告诉我我做错了什么,以及让键盘升起我需要做什么?
我现在已经能够解决这个问题。通过查看InputMethodManager.showSoftInput(View, int)
的代码,我发现我提出键盘的请求被忽略了,因为我传递的视图不是InputMethodManager的活动视图。
为了解决我的问题,我向MyActivity
类添加了两个新字段,即:
private EditText search_edit_text;
private boolean mySearchView_editflag;
search_edit_text
变量将是SearchView mySearchView
内部的视图,该视图实际上是获得焦点并从键盘接收输入的视图。 mySearchView_editflag
通常为假,但在应用程序等待正确的时间打开键盘时为true
。
为了掌握search_edit_text
EditText对象,我使用了以下功能
public static EditText GetEditText(ViewGroup vg) {
for(int i=0; i< vg.getChildCount(); i++) {
View v = vg.getChildAt(i);
if (v instanceof EditText) {
return (EditText)v;
} else if (v instanceof ViewGroup) {
EditText et = GetEditText((ViewGroup)v);
if (et != null) return et;
}
}
return null;
}
并更改了我的onCreateOptionsMenu(Menu)
函数以包括以下内容
DestinationTxt = menu.findItem(R.id.actionbar_search);
mySearchView = (SearchView)DestinationTxt.getActionView();
search_edit_text = GetEditText(mySearchView);
mySearchView_editflag = false;
这将初始化search_edit_text
和mySearchView_editflag
变量。我的onResume()
方法已更改为
@Override
public void onResume() {
super.onResume();
if (startsearch) {
DestinationTxt.expandActionView();
mySearchView_editflag = true;
}
}
并且我包含了频繁调用以下方法的代码:
public void CheckStatus() {
if (mySearchView_editflag && imm.isActive(search_edit_text)) {
imm.showSoftInput(search_edit_text, 0);
mySearchView_editflag=false;
}
}
此应用程序现在可以按我想要的方式运行,因为在需要在操作栏中进行搜索输入时跟随活动切换,因此应用程序现在等待,直到imm.isActive(search_edit_text)
为真(这意味着EditText
对象正在接收输入),然后调用imm.showSoftInput(search_edit_text, 0)
以确保键盘可见。
为了帮助我解决所有这些问题,我使用了InputMethodManager.showSoftInput(View, int, ResultReceiver)
而不是InputMethodManager.showSoftInput(View, int)
,所以代替了
imm.showSoftInput(search_edit_text, 0);
我有
ImmResultsReceiver irr = new ImmResultsReceiver();
imm.showSoftInput(search_edit_text, 0, irr);
其中ImmResultsReceiver
是类
public class ImmResultsReceiver extends ResultReceiver {
public ImmResultsReceiver() { super(null); }
@Override
protected void onReceiveResult (int resultCode, Bundle resultData) {
String descrip;
switch(resultCode) {
case InputMethodManager.RESULT_UNCHANGED_SHOWN: descrip = "RESULT_UNCHANGED_SHOWN"; break;
case InputMethodManager.RESULT_UNCHANGED_HIDDEN: descrip = "RESULT_UNCHANGED_HIDDEN"; break;
case InputMethodManager.RESULT_SHOWN: descrip = "RESULT_SHOWN"; break;
case InputMethodManager.RESULT_HIDDEN: descrip = "RESULT_HIDDEN"; break;
default:descrip="InputMethodManager("+resultCode+")"; break;
}
Log.d("MyLog", "ImmResultsReceiver,"+descrip+","+(resultData == null?"":"resultData.size()="+resultData.size()));
}
}
如果从未调用ImmResultsReceiver.onReceiveResult(...)
方法,则意味着对InputMethodManager.showSoftInput(...)
的调用已被忽略,因为传递给InputMethodManager.showSoftInput(...)
的视图不是InputMethodManager的活动视图。
在清单文件中,尝试将以下内容添加到MyActivity活动部分,以在活动开始时显示键盘:
android:windowSoftInputMode="stateVisible"
这应该使键盘在活动开始时变得可见。
edit
然后在onCreateOptionsMenu
中尝试此..
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.action_menu, menu);
MenuItem menu_search = menu.findItem(actionbar_search);
menu_search.setOnActionExpandListener(new OnActionExpandListener() {
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// Do something when collapsed
return true; // Return true to collapse action view
}
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
//get focus
item.getActionView().requestFocus();
//get input method
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
return true; // Return true to expand action view
}
});
return true;
}
我最后输入的后记。在我延迟切换之前,我检查了InputMethodManager.isActive()是否为false。一切正常,只是在350毫秒后不再应用。因此,在postDelayed中,当延迟的代码运行时,再次检查InputMethodManager.isActive(),如果为true,则不要切换showSoftInput,否则新显示的键盘将消失,这根本不是您想要的。
[糟糕,我认为我的帖子是发布到相关主题的,而不是原始主题的,但是,我所说的是,例如当某个应用被电话打入后台并且当它再次返回时,即使您明确找到具有焦点的EditText并尝试调出它根本不会出现的软键盘。因此,这是我在阅读有关发布Toggle之后使用的代码段...
[请注意,此处引用的“ O”只是我在应用程序中使用的一类静态对象,而imeListener是我用来告诉Fragments发生了什么的回调...
if (O.mInputMethodManager.isActive()) {
if (imeListener != null) {
O.mInputMethodManager.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT,
new ResultReceiver(handler) {
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode == InputMethodManager.RESULT_SHOWN || resultCode == InputMethodManager.RESULT_UNCHANGED_SHOWN) {
imeListener.onSoftKeyboardShown(filenameEditText);
}
}
}
);
}
else {
O.mInputMethodManager.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
}
}
else { // there will be a slight delay...
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (!O.mInputMethodManager.isActive()) { // come right?
O.mInputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
}
if (imeListener != null) {
O.mInputMethodManager.showSoftInput(filenameEditText, InputMethodManager.SHOW_IMPLICIT,
new ResultReceiver(handler) {
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode == InputMethodManager.RESULT_SHOWN || resultCode == InputMethodManager.RESULT_UNCHANGED_SHOWN) {
imeListener.onSoftKeyboardShown(filenameEditText);
}
}
}
);
} else {
O.mInputMethodManager.showSoftInput(filenameEditText, InputMethodManager.SHOW_IMPLICIT);
}
}
}, 350);
}
这是一个古老的问题,但是我遇到了一个类似的问题,该视图具有焦点,但是在InputMethodManager中未激活。通过在requestFocus()之后添加一个延迟,我从上面的一些答案中获取了一个队列。由于我使用的是Kotlin,因此我使用了协程来实现延迟。这样我们就不会阻塞主线程。相关代码如下所示。
Class SomeActivity : AppCompatActivity(), CoroutineScope {
// Create a coroutine job
private val job = Job()
// Implement CoroutineScope
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
// Cancel the job when the activity is destroyed
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
// Shows the keyboard when view has focus
private fun showKeyboard(view: View) {
// start a coroutine
launch {
withContext(Dispatchers.Main) {
// add delay of 300ms
delay(300)
if (currentFocus == view) {
// show the keyboard if view still has focus
(getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
}
}
}
}
}