Як правильно відхилити DialogFragment?


121

Документи говорять про це для dismiss()методу зDialog класу:

Відхиліть це діалогове вікно, видаливши його з екрана. Цей спосіб можна безпечно використовувати з будь-якої нитки. Зауважте, що вам не слід перекривати цей метод, щоб робити очищення, коли діалогове вікно закрито, а реалізувати це в onStop().

У моєму коді все, що я роблю, - це заклик getDialog().dismiss()її відхилити. Але я більше нічого не роблю і навіть не використовую onStop(). Тож я запитую саме, як правильно відмовитись, DialogFragmentщоб уникнути витоків пам’яті тощо.

Відповіді:


197

tl; dr: Правильний спосіб закрити a DialogFragment- це використовувати dismiss() безпосередньо на DialogFragment .


Детальніше : Документація станів DialogFragment

Контроль діалогового вікна (вирішення, коли його показати, приховати, відхилити) повинен здійснюватися через API тут, а не при прямих викликах діалогового вікна.

Таким чином, ви не повинні використовувати getDialog().dismiss(), оскільки це буде викликати dismiss() діалогове вікно . Натомість слід скористатися dismiss()методом самого DialogFragment:

публічне недійсне звільнення ()

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

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

Вам потрібно користуватися лише в тому onStopвипадку, якщо ви явно створили будь-які ресурси, які потребують очищення вручну (закриття файлів, закривання курсорів тощо). Навіть тоді я б onStopзамінив діалоговий фрагмент, а не onStopосновний діалог.


1
@ScootrNova: Це не повинно, ви, ймовірно, маєте помилку в іншому місці. Як ви створюєте фрагмент?
Хайнзі

protected void showDialogFragment(final DialogFragment fragment) {final FragmentTransaction fTransaction = getSupportFragmentManager().beginTransaction(); fTransaction.addToBackStack(null); fragment.show(fTransaction, "dialog");} Вибачте за бридкий один лайнер! Але так, ти можеш мати рацію, тому поки що я написав інший спосіб закрити свої діалогові фрагменти. Те, що я відхилив їх за допомогою методу dismiss (), було просто знайти фрагмент за тегом, а потім запустити на ньому dismiss (), якщо він не був нульовим. О так, так, я newфрагмент прямо перед тим, як передати його до цього методу.
Чарльз Мадере

2
@ScootrNova: Хм, не бачу нічого поганого в цьому - з іншого боку, я ніколи не використовував бібліотеку сумісності, тому не можу бути впевнений у цьому. Можливо, це має сенс створити мінімальний, самодостатній приклад і почати нове питання щодо цього.
Хайнці

@CharlesMadere в ті часи, ти знайшов рішення?
JCarlosR

Вибачте @JCarlos, це було років тому, я не впевнений.
Чарльз Мадере

76

Я думаю, що кращий спосіб закрити DialogFragmentце:

Fragment prev = getSupportFragmentManager().findFragmentByTag("fragment_dialog");
if (prev != null) {
    DialogFragment df = (DialogFragment) prev;
    df.dismiss();
}

Таким чином, вам не потрібно мати посилання на DialogFragmentі можете закривати його звідусіль.


7

Чому б не спробувати використовувати лише цей код:

dismiss();

Якщо ви хочете відхилити діалоговий фрагмент самостійно. Ви можете просто помістити цей код всередині фрагмента діалогу, де ви хочете відхилити діалог.

Наприклад:

button.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       dismiss();
   }
});

Це закриє останній діалоговий фрагмент, який відображається на екрані.

Сподіваюся, це допоможе вам.


не працює весь час
Махмуд Геретані

5

Я дав нагороду на відповідь Тереля. Я просто хотів опублікувати це для будь-яких користувачів Котліна:

supportFragmentManager.findFragmentByTag(TAG_DIALOG)?.let {
    (it as DialogFragment).dismiss()
}

Простий код працює важко, Дякую за оновлення приятелю !!
Айуш Катуваль

4

Відповідь Котліна Версія Тереля

(fragmentManager.findFragmentByTag(TAG) as? DialogFragment)?.dismiss()

1

Ви повинні звільнити вас DialogвonPause() так перевизначити його.

Також перед відхиленням ви можете перевірити nullі відображається, як показано нижче, фрагмент:

@Override
protected void onPause() {
    super.onPause();
    if (dialog != null && dialog.isShowing()) {
        dialog.dismiss();
    }
}

він уже писав, що робить dismiss () і його про DialogFragment.
Paresh Mayani

Я вважаю , що це працює як для Dialog і DialogFragments @PareshMayani
Venky

2
Я вважаю, що @PareshMayani є правильним Венкі. У навчальному посібнику DialogFragmentGoogle не відображається onPause()метод, який використовується взагалі. Але я думаю, я бачу, що ти робиш. У чому сенс, якщо користувач не дзвонить onPause(). Це коли система знає, що фрагмент викликається. Як щодо того, коли, скажімо, користувач скасовує. Який кращий спосіб закрити його в такому випадку?
Енді

1

У інших відповідях є посилання на офіційні документи ( довідник DialogFragment ), але жодного згадування про приклад, наведений там:

void showDialog() {
    mStackLevel++;

    // DialogFragment.show() will take care of adding the fragment
    // in a transaction.  We also want to remove any currently showing
    // dialog, so make our own transaction and take care of that here.
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment prev = getFragmentManager().findFragmentByTag("dialog");
    if (prev != null) {
        ft.remove(prev);
    }
    ft.addToBackStack(null);

    // Create and show the dialog.
    DialogFragment newFragment = MyDialogFragment.newInstance(mStackLevel);
    newFragment.show(ft, "dialog");
}

Це видаляє будь-який показаний в даний час діалог, створює новий DialogFragment з аргументом і показує його як новий стан на задній стеці. Після трансакції транзакції поточний DialogFragment та його Dialog будуть знищені, а попередній (якщо такий є) повторно показаний. Зауважте, що в цьому випадку DialogFragment піклується про те, щоб транзакція діалогового вікна відхиляється окремо від неї.

Для моїх потреб я змінив його на:

FragmentManager manager = getSupportFragmentManager();
Fragment prev = manager.findFragmentByTag(TAG);
if (prev != null) {
    manager.beginTransaction().remove(prev).commit();
}

MyDialogFragment fragment = new MyDialogFragment();
fragment.show(manager, TAG);

1

Додаючи до інших відповідей, якщо DialogFragmentдзвінок на повний екран dismiss()не викличе DialogFragment з задніх фрагментів. Вирішення питання - зателефонуватиonBackPressed() до батьківської діяльності.

Щось на зразок цього:

CustomDialogFragment.kt

closeButton.onClick {
    requireActivity().onBackPressed()
}

Врятуйте день, велике спасибі
Махмуд Геретані

0

Просто зателефонуйте dismiss () з фрагменту, який ви хочете відхилити.

imageView3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            dismiss();
        }
    });

0

Я виявив, що коли мій фрагмент був визначений у графіку навігації з <fragment>тегом (для діалогового фрагмента на весь екран), діалоговий фрагмент не буде відхилено dismiss()командою. Натомість мені довелося вискакувати задній стек:

findNavController(getActivity(), R.id.nav_host_fragment).popBackStack();

Однак, якщо той самий діалоговий фрагмент був визначений у навігаційному графіку з <dialog>тегом, dismiss()працює добре.


0
CustomFragment dialog = (CustomDataFragment) getSupportFragmentManager().findFragmentByTag("Fragment_TAG");
if (dialog != null) {
  dialog.dismiss();
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.