Виявити кнопку повернення, але не відхиляти діалоговий фрагмент


77

У мене є діалоговий фрагмент для плаваючого діалогового вікна, що включає спеціальну клавіатуру, яка з’являється, коли користувач натискає всередині поля EditText (нормальний IME не відображається).

Я хотів би, щоб клавіатура була відхилена (visibility = GONE), коли користувач натискає кнопку "Назад" (як у звичайній службі IME), але діалогове вікно залишається видимим. Однак, схоже, не існує способу зробити це, наскільки я бачу з мого досить широкого читання про SO та деінде.

Якщо я встановив діалогове вікно, яке не можна скасувати, тоді я не отримую сповіщення onCancel () або onDismiss (), оскільки діалогове вікно не можна скасувати.

Якщо я встановлю діалогове вікно, яке можна скасувати, я отримую повідомлення, але діалогове вікно відхиляється.

Я не можу приєднати onKeyListener до діалогового вікна у фрагменті, оскільки він замінений системою, щоб фрагмент міг обробляти життєвий цикл діалогового вікна.

Чи є спосіб зробити це? Або доступ до виявлення ключових подій був повністю відгороджений для цілей системи Fragment?

Відповіді:


179

Найкращий спосіб і найчистіший спосіб - це перевизначення onBackPress () у діалоговому вікні, яке ви створили в onCreateDialog ().

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new Dialog(getActivity(), getTheme()){
        @Override
        public void onBackPressed() {
            //do your stuff
        }
    };
}

9
Єдине рішення, яке я виявив, насправді працює належним чином.
Йоанн Еркуе,

6
Це не працює в DialogFragments, хоча, оскільки в класі DialogFragment немає onBackPress ().
Глен Пірс,

10
DialogFragments обгортає Dialog - onCreateDialog створює це діалогове вікно. Це працює в DialogFragments.
Том

Я можу лише підтвердити це як найкраще та найпростіше рішення. Дякуємо, що поділились цим @Ian Wong
Menion Asamm

1
Однозначно має бути прийнятою відповіддю. Найбільш рідне рішення на сьогоднішній день!
egorikem

78

У мене була та ж проблема, що і у вас, і я виправив її, приєднавши onKeyListener до діалогового фрагмента.

У метод onResume()класу, що поширюється на DialogFragment, помістіть такий шматок коду:

    getDialog().setOnKeyListener(new OnKeyListener()
    {
        @Override
        public boolean onKey(android.content.DialogInterface dialog, int keyCode,android.view.KeyEvent event) {

            if ((keyCode ==  android.view.KeyEvent.KEYCODE_BACK))
                {
                     //Hide your keyboard here!!!
                     return true; // pretend we've processed it
                }
            else 
                return false; // pass on to be processed as normal
        }
    });

Тут одна з проблем, яку ви можете виявити, полягає в тому, що цей код буде виконуватися двічі: одна, коли користувач натискає кнопку "Назад", і інша, коли він йде, щоб натиснути її. У цьому випадку вам доведеться відфільтрувати за подією:

@Override
public void onResume() {
    super.onResume();

    getDialog().setOnKeyListener(new OnKeyListener()
    {
        @Override
        public boolean onKey(android.content.DialogInterface dialog, int keyCode,
                android.view.KeyEvent event) {

            if ((keyCode ==  android.view.KeyEvent.KEYCODE_BACK))
            {
                //This is the filter
                if (event.getAction()!=KeyEvent.ACTION_DOWN)
                        return true;
                else
                {
                    //Hide your keyboard here!!!!!!
                    return true; // pretend we've processed it
                }
            } 
            else 
                return false; // pass on to be processed as normal
        }
    });
}

Замість того, щоб використовувати фільтр, я додав getDialog (). SetOnKeyListener (null), який запобігає другому виклику.
Лукас Аррефельт,

24

Як доповнення до відповіді Хуана Педро Мартінеса, я вважав, що було б корисно пояснити конкретне запитання (одне, яке я мав), розглядаючи цю тему.

Якщо ви хочете створити новий DialogFragment і мати його таким чином, щоб користувач міг скасувати його лише за допомогою кнопки "Назад", що виключає випадкові дотики до екрана від передчасного скасування фрагмента, тоді це код, який ви б використовували.

У будь-якому коді, який ви називаєте DialogFragment, вам потрібно встановити для параметра скасовуваного значення значення false, щоб НІЩО не відхиляло фрагмент, не торкалося екрана і т.д.

DialogFragment mDialog= new MyDialogFragment();
mDialog.setCancelable(false);
mDialog.show(getFragmentManager(), "dialog");

Потім, у вашому DialogFragment, у цьому випадку MyDaialogFragment.java, ви додаєте код перевизначення onResume, щоб діалогове вікно прослуховувало кнопку Назад. Після натискання він виконує функцію dismiss (), щоб закрити фрагмент.

@Override
 public void onResume() 
 {
     super.onResume();

     getDialog().setOnKeyListener(new OnKeyListener()
     {
         @Override
         public boolean onKey(android.content.DialogInterface dialog, 
                              int keyCode,android.view.KeyEvent event) 
         {
              if ((keyCode ==  android.view.KeyEvent.KEYCODE_BACK))
              {
                   // To dismiss the fragment when the back-button is pressed.
                   dismiss();
                   return true;
              }
              // Otherwise, do nothing else
              else return false;
         }
   });

Тепер ваше діалогове вікно буде викликано за допомогою "setCancelable" на false, тобто ніщо (жодні зовнішні клацання) не зможе його скасувати і вимкнути, а також дозволить (з самого діалогового вікна) закрити його лише кнопкою "Назад".

Ганбатте!


1
Прекрасно, дякую, я хотів запобігти випадковим зовнішнім клацанням, зберігаючи при цьому функціональність кнопки "Назад". Для мене все, що мені потрібно було встановити OfficeCaleble (false) у діалоговому екземплярі в onCreateView всередині DialogFragment.
Meanman

1
Дякую, ця відповідь найбільше відповідає моєму стану.
Araju

16

Як ніхто цього не запропонував?

public Dialog onCreateDialog(Bundle savedInstanceState) {
  Dialog dialog = super.onCreateDialog(savedInstanceState);

  // Add back button listener
  dialog.setOnKeyListener(new Dialog.OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialogInterface, int keyCode, KeyEvent keyEvent) {
      // getAction to make sure this doesn't double fire
      if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.getAction() == KeyEvent.ACTION_UP) {
        // Your code here
        return true; // Capture onKey
      }
      return false; // Don't capture
    }
  });

  return dialog;
}

15

Використовуйте метод перевизначення Fragment onCancel. Це викликається, коли ви натискаєте назад. ось зразок:

@Override
public void onCancel(DialogInterface dialog) {
    super.onCancel(dialog);

    // Add you codition
}

2
Зауважте, що за допомогою цього підходу ви не можете вирішити, буде відхилено DialogFragment чи ні. Ви можете просто отримати повідомлення про те, що його слід звільнити
Leo Droidcoder

Дійсно @Leo Droidcoder Будь-яка ідея, як перехопити кнопку назад, натиснуту до того, як діалоговий фрагмент не можна відхилити?
matdev

3

Створюючи діалогове вікно, перевизначте onBackPress та onTouchEvent:

        final Dialog dialog = new Dialog(activity) {
            @Override
            public boolean onTouchEvent(final MotionEvent event) {
                //note: all touch events that occur here are outside the dialog, yet their type is just touching-down
                boolean shouldAvoidDismissing = ... ;
                if (shouldAvoidDismissing) 
                    return true;
                return super.onTouchEvent(event);
            }

            @Override
            public void onBackPressed() {
                boolean shouldAvoidDismissing = ... ;
                if (!shouldSwitchToInviteMode)
                    dismiss();
                else
                    ...
            }
        };

0

Використовуйте зворотний виклик onDismiss () DialogFragment з прапором closeActivity

private var closeActivity: Boolean = true    

override fun onDismiss(dialog: DialogInterface?) {
        super.onDismiss(dialog)

        if (closeActivity) {
            activity!!.finish()
        }
    }

0

Запобігання скасуванню DialogFragment:

dialog.setCanceledOnTouchOutside(false)
dialog.setCancelable(false)
dialog.setOnKeyListener { dialog, keyCode, event ->
    keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP
}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.