0

Вот проект, показывающий, что работает, а что нет. Код также ниже. Я нашел много сообщений stackoverflow, показывающих четкое решение для этого, но по какой-то причине это не работает для меня, если я не запустил его в фоновом потоке.Force show keyboard не работает, если вы не запускаете фоновый поток

Я создаю AlertDialog и EditText. Моя цель - показать диалоговое окно предупреждения, показать клавиатуру и поместить курсор в текст редактирования. По какой-то причине я не могу просто RequestFocus и ShowSoftInput. Он работает только тогда, когда я создаю фоновый поток, а затем звоню ... Почему? Я делаю что-то неправильно?

enter image description hereenter 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

Почему клавиатура не отображается, когда вы вызываете this.ForceShowKeyboard(editText); напрямую.

Вы можете найти диалоговый исходный код here, когда вы показываете диалог, он отправит SHOW сообщений для обработчика, а затем пусть поток пользовательского интерфейса, чтобы показать диалоговое окно.

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 будет отправлен в очередь событий потока пользовательского интерфейса. Это означает, что он будет запускаться при создании диалога. Таким образом, вы можете увидеть клавиатуру.

Проверяя исходный код RunOnUIThread(), он также является обработчиком.

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

Другими словами, если ваш диалог создан, он будет посылать сообщение в обработчик потока UI, и обработчик сделает EditText фокус.

Получите информацию об Андроид-манипуляторе, это поможет вам понять.