除非您在后台线程中运行,否则强制显示键盘不起作用

时间:2017-02-07 16:57:23

标签: android xamarin android-edittext xamarin.android alertdialog

这里的项目展示了哪些有效,哪些无效。代码也在下面。我发现很多stackoverflow帖子显示了明确的解决方案,但由于某种原因,除非我在后台线程中运行,否则这对我没有用。

我正在创建一个AlertDialog和一个EditText。我的目标是显示警告对话框,显示键盘,并在编辑文本中显示光标。出于某种原因,我不能只是RequestFocus和ShowSoftInput。它只适用于我创建后台线程,然后拨打电话......为什么?难道我做错了什么?

enter image description here enter image description here

这是我在后台线程中运行代码时应用程序的样子截图,而不是...

链接到Xamarin Android项目: https://drive.google.com/open?id=0B5x7JEZ8aQihVnM4am8yRWlQYkU

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        // Get our button from the layout resource,
        // and attach an event to it
        Button button = FindViewById<Button>(Resource.Id.myButton);

        button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };



        AlertDialog.Builder alertBuilder = new AlertDialog.Builder(this);
        AlertDialog alertDialog = null;
        TextView titleTV = new TextView(this);
        titleTV.Text = "title";
        titleTV.TextSize = 18f;
        titleTV.SetTextColor(Android.Graphics.Color.Green);
        titleTV.SetBackgroundColor(Android.Graphics.Color.White);
        titleTV.SetPadding(0, 12, 0, 12);
        titleTV.Gravity = GravityFlags.CenterHorizontal | GravityFlags.CenterVertical;
        alertBuilder.SetCustomTitle(titleTV);

        EditText editText = new EditText(this);
        editText.SetHeight(600); 
        editText.Text = "super coooool dude";
        editText.TextSize = 14f;
        editText.SetPadding(18, 12, 18, 12);
        editText.Gravity = GravityFlags.Left | GravityFlags.Top;
        editText.ShowSoftInputOnFocus = true;
        editText.RequestFocus();
        alertBuilder.SetView(editText);
        alertBuilder.SetPositiveButton("Done", (sender, e) => { });
        alertBuilder.SetNegativeButton("Cancel", (sender, e) => { });

        alertDialog = alertBuilder.Create();
        alertDialog.Show();



        // STACKOVERFLOW LOOK HERE.  

        //// Calling ForceShowKeyboard does not work here..... Why?  
        //this.ForceShowKeyboard(editText);

        // But, calling ForceShowKeyboard works when in a background thread, sleeping a bit, then run on main thread again
        Thread t = new Thread(() => this.DoThreadSTuff(editText));
        t.IsBackground = true;
        t.Start();
    }

    private void DoThreadSTuff(EditText editText)
    {
        // I dont think a sleep is needed, but i found a similar issue in Xamarin.iOS once upon a time, and a sleep was needed.  It seems Xamarin.Android doesn't require a sleep though.  
        //Thread.Sleep(2);

        RunOnUiThread(() =>
        {
            this.ForceShowKeyboard(editText);
        });
    }

    private void ForceShowKeyboard(EditText editText)
    {
        editText.RequestFocus();
        InputMethodManager imm = (InputMethodManager)this.GetSystemService(Android.Content.Context.InputMethodService);
        imm.ShowSoftInput(editText, ShowFlags.Implicit);
    }

1 个答案:

答案 0 :(得分:1)

  

为什么直接拨打this.ForceShowKeyboard(editText);时键盘无法显示。

您可以找到对话框源代码here,当您显示对话框时,它会向处理程序发送SHOW消息,然后让UI线程显示对话框。

   public void show() {

       ......

        sendShowMessage();
    }

   private void sendShowMessage() {
        if (mShowMessage != null) {
            // Obtain a new message so this dialog can be re-used
            Message.obtain(mShowMessage).sendToTarget();
        }
    }

    .....
    mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);


   private static final class ListenersHandler extends Handler {
   ......
     @Override
     public void handleMessage(Message msg) {
        switch (msg.what) {
            ......
            case SHOW:
                ((OnShowListener) msg.obj).onShow(mDialog.get());
                break;
        }
     }
   }

所以Dialog.Show()是异步方法。

这意味着在对话显示之前将调用this.ForceShowKeyboard(editText);。所以你看不到键盘。

  

为什么在后台线程中运行代码时会显示键盘。

您在另一个主题中调用RunOnUIThread()RunOnUIThread的委托将被发布到UI线程的事件队列中。这意味着它将在您创建对话框时运行。所以你可以看到键盘。

通过检查RunOnUIThread()的源代码,它也是一个处理程序。

public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

换句话说,当你创建对话框时,它会向UI线程处理程序发送一条消息,处理程序将使EditText成为焦点。

了解Android Handler,它将帮助您理解。