即使明确要求,Android 键盘也不会出现

Sto*_*lly 1 android android-keypad android-actionbar android-search

我有一个包含两个活动的应用程序,有时,我需要切换活动,同时在刚刚恢复的活动的操作栏中打开搜索输入。一切正常,只是我无法让键盘出现。我的代码的相关部分如下(注意:true如果需要搜索输入,则布尔值 startsearch 设置为切换活动的结果):

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和 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>
Run Code Online (Sandbox Code Playgroud)

正如我所说,这主要是有效的,因为当活动恢复时,操作栏搜索确实获得了焦点。但是键盘没有出现,即使(正如您从代码中看到的那样),我已经明确要求它。谁能告诉我我做错了什么,我需要做什么才能让键盘出现?

Sto*_*lly 5

我现在已经能够弄清楚这一点。通过查看 的代码InputMethodManager.showSoftInput(View, int),我发现我调出键盘的请求被忽略了,因为我传递的视图不是 InputMethodManager 的活动视图。

为了解决我的问题,我在MyActivity类中添加了两个新字段,即:

private EditText search_edit_text;
private boolean mySearchView_editflag;
Run Code Online (Sandbox Code Playgroud)

search_edit_text变量将是内部的SearchView mySearchView视图,它是实际获得焦点并接收来自键盘的输入的视图。在mySearchView_editflag通常是假的,但它会true在应用程序正在等待合适的时机来调出键盘。

为了获得search_edit_textEditText 对象,我使用了以下函数

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;
}
Run Code Online (Sandbox Code Playgroud)

并更改了我的onCreateOptionsMenu(Menu)功能以包括以下内容

DestinationTxt = menu.findItem(R.id.actionbar_search);
mySearchView = (SearchView)DestinationTxt.getActionView();
search_edit_text = GetEditText(mySearchView);
mySearchView_editflag = false;
Run Code Online (Sandbox Code Playgroud)

这将初始化search_edit_textmySearchView_editflag变量。我的onResume()方法被更改为

@Override
public void onResume() {
    super.onResume();
    if (startsearch) {
        DestinationTxt.expandActionView();
        mySearchView_editflag = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

我包含了高频调用以下方法的代码:

public void CheckStatus() {
    if (mySearchView_editflag && imm.isActive(search_edit_text)) {
        imm.showSoftInput(search_edit_text, 0);
        mySearchView_editflag=false;
    }
}
Run Code Online (Sandbox Code Playgroud)

这个应用程序现在可以像我想要的那样工作,因为在需要操作栏中的搜索输入时跟随活动切换,应用程序现在等待直到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);
Run Code Online (Sandbox Code Playgroud)

我有

ImmResultsReceiver irr = new ImmResultsReceiver();
imm.showSoftInput(search_edit_text, 0, irr);
Run Code Online (Sandbox Code Playgroud)

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()));
    }               
}
Run Code Online (Sandbox Code Playgroud)

如果ImmResultsReceiver.onReceiveResult(...)从未调用过该方法,则意味着调用InputMethodManager.showSoftInput(...)已被忽略,因为传递给的视图InputMethodManager.showSoftInput(...)不是 InputMethodManager 的活动视图。

  • .....Google 所做的 ROFL 让简单的事情变得如此复杂,比如去 Area51 (3认同)