【问题标题】:Android keyboard not appearing, even when explicitly requested即使明确要求,Android 键盘也不会出现
【发布时间】:2013-05-28 05:35:45
【问题描述】:

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

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

【问题讨论】:

    标签: android android-actionbar android-keypad android-search


    【解决方案1】:

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

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

    private EditText search_edit_text;
    private boolean mySearchView_editflag;
    

    search_edit_text 变量将是 SearchView mySearchView 内部的视图,它是实际获得焦点并接收键盘输入的视图。 mySearchView_editflag 通常为 false,但当应用程序等待合适的时间调出键盘时,它将为 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_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 的活动视图。

    【讨论】:

    • .....Google 所做的 ROFL 让简单的事情变得像去 Area51 一样复杂
    【解决方案2】:

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

    android:windowSoftInputMode="stateVisible"
    

    这应该会导致键盘在 Activity 启动时变得可见。

    编辑

    然后在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;
    }
    

    【讨论】:

    • 感谢您的建议,但这会使键盘一直出现。我只希望它在操作栏中的搜索被激活时出现。
    • 感谢您的建议,但这似乎也不起作用。我认为问题可能是在onResume(...) 期间调用了您的建议和我最初的尝试(发布在问题中)。因此,活动可能没有完全“营业”,因此对 InputMethodManager 的调用会丢失/被忽略。
    • 以防万一您有兴趣,我认为我已经能够找到一种方法来做到这一点,请参阅我刚刚发布的答案。
    【解决方案3】:

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

    【讨论】:

    • 很难理解你的答案,请附上一些例子。
    【解决方案4】:

    哎呀,我想我把我的后记发布到了一个相关的线程,而不是原来的,但是我所说的是当一个应用程序被一个电话强制进入后台时,即使你明确找到具有焦点的 EditText 并尝试调出它根本不会出现的软键盘。所以这是我在阅读了关于发布 Toggle 后使用的代码 sn-p...

    请注意,此处引用的“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);
        }
    

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多