1

我有一个包含两个活动的应用程序,有时,我需要切换活动,同时在刚刚恢复的活动的操作栏中打开搜索输入。一切正常,除了我无法启动键盘。我的代码的相关位如下(注意: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);
        }
    }
}

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>

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

4

5 回答 5

6

我现在已经能够弄清楚这一点。通过查看 的代码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_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;
}

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

DestinationTxt = menu.findItem(R.id.actionbar_search);
mySearchView = (SearchView)DestinationTxt.getActionView();
search_edit_text = GetEditText(mySearchView);
mySearchView_editflag = false;

这将初始化search_edit_textmySearchView_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 的活动视图。

于 2013-06-02T12:25:37.693 回答
2

在清单文件中,尝试将以下内容添加到MyActivity活动部分以在活动开始时显示键盘:

android:windowSoftInputMode="stateVisible"

这应该会导致键盘在活动开始时变得可见。

编辑

然后在里面试试这个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;
}
于 2013-06-01T14:11:35.040 回答
0

哎呀,我想我把我的后记发布到了一个相关的线程,而不是原来的,但是我所说的是当一个应用程序被一个电话强制进入后台时,即使你明确找到具有焦点并尝试调出软键盘的 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);
    }
于 2015-08-07T01:44:45.277 回答
0

我上次输入的后记。在我发布延迟切换之前,我检查了 InputMethodManager.isActive() 是否为假。一切都很好,只是 350 毫秒后它不再适用。因此,在您的 postDelayed 中,当您的延迟代码运行时,再次检查 InputMethodManager.isActive(),如果为 true,则不要切换仅 showSoftInput,否则新可见的键盘将消失,这根本不是人们想要的。

于 2015-08-05T17:41:16.367 回答
0

这是一个老问题,但我遇到了一个类似的问题,视图有焦点,但在 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)
                }
            }
        }
    }

}
于 2019-12-30T20:31:30.343 回答