Android DialogFragment 和 onDismiss

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23786033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:26:43  来源:igfitidea点击:

DialogFragment and onDismiss

androidandroid-dialogfragment

提问by deimos1988

I am using a DialogFragment, which I am showing like this from an Activity:

我正在使用 a DialogFragment,我从 an 显示如下Activity

DialogFragmentImage dialog = DialogFragmentImage.newInstance(createBitmap());
dialog.onDismiss(dialog);.onDismiss(this);          
dialog.show(getFragmentManager(), "DialogFragmentImage");

I would like to check when the DialogFragmentwas dismissed (for example when the back button was pressed), but in my Activity. How can I do that? How can I "tell" my activitythat the DialogFragmenthas been dismissed?

我想检查何时DialogFragment被解雇(例如,当按下后退按钮时),但在我的Activity. 我怎样才能做到这一点?我如何“告诉”我activityDialogFragment已被解雇?

回答by Yaroslav Mytkalyk

Make your Activity implement OnDismissListener

使您的 Activity 实施 OnDismissListener

public final class YourActivity extends Activity implements DialogInterface.OnDismissListener {

    @Override
    public void onDismiss(final DialogInterface dialog) {
        //Fragment dialog had been dismissed
    }

}

DialogFragment already implements OnDismissListener, just override the method and call the Activity.

DialogFragment 已经实现OnDismissListener,只需覆盖该方法并调用 Activity。

public final class DialogFragmentImage extends DialogFragment {

    ///blah blah

    @Override
    public void onDismiss(final DialogInterface dialog) {
        super.onDismiss(dialog);
        final Activity activity = getActivity();
        if (activity instanceof DialogInterface.OnDismissListener) {
            ((DialogInterface.OnDismissListener) activity).onDismiss(dialog);
        }
    }

}

If you're starting the dialog from a fragment using the childFragmentmanager (API>=17), you can use getParentFragmentto talk to the onDismissListener on the parent fragment.:

如果您使用childFragment管理器 (API>=17)从片段启动对话框,则可以使用getParentFragment与父片段上的 onDismissListener 对话。:

public final class DialogFragmentImage extends DialogFragment {

    ///blah blah

    @Override
    public void onDismiss(final DialogInterface dialog) {
        super.onDismiss(dialog);
        Fragment parentFragment = getParentFragment();
        if (parentFragment instanceof DialogInterface.OnDismissListener) {
            ((DialogInterface.OnDismissListener) parentFragment).onDismiss(dialog);
        } 
    }

}

回答by Boonya Kitpitak

Here is my answer. It's a bit late but it's maybe benefit someone passing by.

这是我的答案。有点晚了,但也许对路过的人有益。

FragmentManager fm = getFragmentManager();

YourDialogFragment dialog = new YourDialogFragment();
dialog.show(fm,"MyDialog");

fm.executePendingTransactions();
dialog.getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialogInterface) {
                       //do whatever you want when dialog is dismissed
                    }
                });

We need to call

我们需要打电话

fm.executePendingTransactions(); 

To make sure that FragmentTransaction work has been performed. Otherwise NullPointerExceptioncan occur when calling setOnDismissListener().

确保已执行 FragmentTransaction 工作。否则NullPointerException在调用setOnDismissListener().

Sorry if there is any mistake. Hope this help.

如有错误,请见谅。希望这有帮助。

回答by Kaskasi

This is an old issue but I found no solution I am happy with. I don't like passing any Listeners to my DialogFragment or set a TargetFragment, because that may break on orientation change. What do you think about this?

这是一个老问题,但我没有找到令我满意的解决方案。我不喜欢将任何侦听器传递给我的 DialogFragment 或设置 TargetFragment,因为这可能会在方向更改时中断。你怎么看待这件事?

        MyDialog d = new MyDialog();
        d.show(fragmentManager, "tag");
        fragmentManager.registerFragmentLifecycleCallbacks(new FragmentManager.FragmentLifecycleCallbacks() {
            @Override
            public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {
                super.onFragmentViewDestroyed(fm, f);
                //do sth      
        fragmentManager.unregisterFragmentLifecycleCallbacks(this);
                }
            }, false);

回答by Anthone

Alternative answer, if you don't have access to the methode onDismiss of activity.

替代答案,如果您无权访问 onDismiss of 活动的方法。

//DIALOGFRAGMENT
//Create interface in your DialogFragment (or a new file)
public interface OnDismissListener {
   void onDismiss(MyDialogFragment myDialogFragment);
}
//create Pointer and setter to it
private OnDismissListener onDismissListener;
public void setDissmissListener(DissmissListener dissmissListener) {
   this.dissmissListener = dissmissListener;
}
//Call it on the dialogFragment onDissmiss
@Override
public void onDismiss(DialogInterface dialog) {
   super.onDismiss(dialog);

   if (onDismissListener != null) {
      onDismissListener.onDismiss(this);
   }
}

//OTHER CLASS, start fragment where you want
MyDialogFragment df = new MyDialogFragment();
df.setOnDismissListener(new MyDialogFragment.OnDismissListener() {
   @Override
   public void onDismiss(MyDialogFragment myDialogFragment) {
      //Call when MyDialogFragment close
   }
});
df.show(activity.getFragmentManager(), "myDialogFragment");

edit :if system need to recreate DialogFragment: you can find it with

编辑:如果系统需要重新创建DialogFragment:你可以找到它

MyDialogFragment myDialogFragment = getFragmentManager().findFragmentByTag("MyDialogFragment"); 
if(myDialogFragment != null) { 
   myDialogFragment.setOnDismissListener(...); 
}

回答by d3roch4

public class OpcoesProdutoDialogo extends DialogFragment{
    private DialogInterface.OnDismissListener onDismissOuvinte;
.
.
.

@Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        if(onDismissOuvinte!=null)
            onDismissOuvinte.onDismiss(dialog);
    }

    public void setOnDismissListener(@Nullable DialogInterface.OnDismissListener listener) {
        this.onDismissOuvinte = listener;
    }
}

and in call

并在通话中

OpcoesProdutoDialogo opcProduto = OpcoesProdutoDialogo.criar(itemPedido);
        opcProduto.show(getFragmentManager(), "opc_produto_editar");
        opcProduto.setOnDismissListener(d->{
            adapterItens.notifyItemChanged(posicao);
        });

回答by Minas Mina

If you don't like the solution of @yaroslav-mytkalyk, in which the fragment needs to cast the activity / parent fragment, here's another one:

如果你不喜欢@yaroslav-mytkalyk 的解决方案,其中片段需要转换活动/父片段,这是另一个:

Here's the idea:

这是想法:

  1. Expose a listener in your fragment, DialogFragmentImage.
  2. Implement the listener in your activity and pass it to the fragment when creating it. Make sure to use a tag as well in order to be able to find the fragment later (read below).
  3. In onStop(), remove the listener in order not to leak the activity if it's destroyed. This will happen when the screen is rotated, as the activity will be re-created.
  4. In onResume(), check if the fragment exists and if yes, re-add the listener.
  1. 在您的片段中公开一个侦听器,DialogFragmentImage.
  2. 在您的活动中实现侦听器并在创建它时将其传递给片段。确保也使用标签,以便以后能够找到片段(阅读下文)。
  3. 在 中onStop(),删除侦听器,以免活动被破坏时泄漏。这将在屏幕旋转时发生,因为活动将被重新创建。
  4. 在 中onResume(),检查片段是否存在,如果存在,则重新添加侦听器。


Expose a listener from your fragment:

从您的片段公开一个侦听器:

class MyFragment extends DialogFragment {

    public interface OnDismissListener {
        void dismissed();
    }

    @Nullable
    private OnDismissListener onDismissListener;

    public void setOnDismissListener(@Nullable OnDismissListener onDismissListener) {
        this.onDismissListener = onDismissListener;
    }

    /*
    If you are calling dismiss() or dismissAllowingStateLoss() manually,
    don't forget to call:
    if (onDismissListener != null) {
        onDismissListener.dismissed();
    }

    Otherwise, override them and call it there.
    */
}

And this is how your activity should look like:

这就是您的 Activity 的外观:

class MyActivity extends AppCompatActivity {

    private static final String MY_FRAGMENT_TAG = "my_fragment";

    private MyFragment.OnDismissListener myFragmentListener = () -> {

        // ...
    };

    /**
     * Shows the fragment. Note that:
     * 1. We pass a tag to `show()`.
     * 2. We set the listener on the fragment.
     */
    private void showFragment() {

        MyFragment fragment = new MyFragment();
        fragment.show(getSupportFragmentManager(), MY_FRAGMENT_TAG);
        fragment.setOnDismissListener(myFragmentListener);
    }

    @Override
    protected void onStart() {

        super.onStart();

        // Restore the listener that we may have removed in `onStop()`.
        @Nullable MyFragment myFragment =  (MyFragment) getSupportFragmentManager().findFragmentByTag(MY_FRAGMENT_TAG);
        if (myFragment != null) {
            myFragment.setOnDismissListener(myFragmentListener);
        }
    }

    @Override
    protected void onStop() {

        // If the fragment is currently shown, remove the listener so that the activity is not leaked when e.g. the screen is rotated and it's re-created.
        @Nullable MyFragment myFragment =  (MyFragment) getSupportFragmentManager().findFragmentByTag(MY_FRAGMENT_TAG);
        if (myFragment != null) {
            myFragment.setOnDismissListener(null);
        }

        super.onStop();
    }
}

回答by Zhar

Care : all example aren't correct because your fragment should have a no-arg constructor !

注意:所有示例都不正确,因为您的片段应该有一个无参数构造函数!

Working code with back gesture and close button in the fragment itself. I removed useless code stuff like getting arg in onCreateetc.

片段本身中带有后退手势和关闭按钮的工作代码。我删除了无用的代码内容,例如获取 argonCreate等。

Important : onDismissis also call when orientation change so as a result you should check if the context is not null in your callback(or using other stuff).

重要提示:onDismiss在方向更改时也会调用,因此您应该检查回调中的上下文是否为空(或使用其他内容)。

public class MyDialogFragment extends DialogFragment {

    public static String TAG = "MyFragment";

    public interface ConfirmDialogCompliant {
        void doOkConfirmClick();
    }


    public MyFragment(){
        super();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_layout, container, false);

        ((ImageButton) rootView.findViewById(R.id.btn_close)).setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // close fragment
                dismiss();
            }
        });
        return rootView;
    }

    @Override
    public void onDismiss(@NonNull DialogInterface dialog) {
        super.onDismiss(dialog);
        // notify
        if(caller != null)
           caller.doOkConfirmClick();
        }
    }

  public void setCallback(ConfirmDialogCompliant caller) {
    this.caller = caller;
  }

 public static MyDialogFragment newInstance(String id) {
    MyDialogFragment f = new MyDialogFragment();

    // Supply num input as an argument.
    Bundle args = new Bundle();
    args.putString("YOU_KEY", id);
    f.setArguments(args);

    return f;
}

}

}

And now how to call it from parent.

现在如何从父级调用它。

MyDialogFragment.ConfirmDialogCompliant callback = new MyDialogFragment.ConfirmDialogCompliant() {

            @Override
            public void doOkConfirmClick() {
                // context can be null, avoid NPE
                if(getContext() != null){

                }

            }

        };

    MyDialogFragment fragment = MyDialogFragment.newInstance("item");
    fragment.setCallback(callback);
    fragment.show(ft, MyDialogFragment.TAG);
        new MyDialogFragment(callback, item);

    fragment.show(getActivity().getSupportFragmentManager(), MyDialogFragment.TAG);

Additionnal source : https://developer.android.com/reference/android/app/DialogFragment

其他来源:https: //developer.android.com/reference/android/app/DialogFragment

回答by Preslav Petkov

You can subclass DialogFragment and provide your own listener that is going to be called and in onCancel.

您可以继承 DialogFragment 并提供您自己的侦听器,该侦听器将在 onCancel 中被调用。

var onDismissListener: (() -> Unit)? = null

For the ones not familiar with Kotlin this is just an anonymous interface that saves boilerplate iterface in Java. Use a field and a setter in Java.

对于那些不熟悉 Kotlin 的人来说,这只是一个匿名接口,可以在 Java 中保存样板 iterface。在 Java 中使用字段和设置器。

And then in onCancel

然后在 onCancel

    override fun onCancel(dialog: DialogInterface?) {
    super.onCancel(dialog)
    onDismissListener?.invoke()
}

Have fun!

玩得开心!