简体   繁体   English

DialogFragment 和 onDismiss

[英]DialogFragment and onDismiss

I am using a DialogFragment , which I am showing like this from an Activity :我正在使用DialogFragment ,我从Activity显示如下:

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

I would like to check when the DialogFragment was dismissed (for example when the back button was pressed), but in my Activity .我想检查DialogFragment被解除(例如按下后退按钮时),但在我的Activity中。 How can I do that?我怎样才能做到这一点? How can I "tell" my activity that the DialogFragment has been dismissed?如何“告诉”我的activity DialogFragment已被解除?

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 childFragment manager (API>=17), you can use getParentFragment to 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);
        } 
    }

}

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.确保已执行 FragmentTransaction 工作。 Otherwise NullPointerException can occur when calling setOnDismissListener() .否则调用setOnDismissListener()时可能会发生NullPointerException

Sorry if there is any mistake.如有错误请见谅。 Hope this help.希望这有帮助。

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.我不喜欢将任何侦听器传递给我的 DialogFragment 或设置 TargetFragment,因为这可能会在方向更改时中断。 What do you think about this?你怎么看待这件事?

        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);

Alternative answer, if you don't have access to the methode onDismiss of activity.替代答案,如果您无权访问活动的 onDismiss 方法。

//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(...); 
}
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);
        });

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 .在片段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.onStop()中,移除监听器,以免活动被破坏时泄漏。 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.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:这就是你的活动应该是这样的:

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();
    }
}

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 onCreate etc.我删除了无用的代码内容,例如在onCreate中获取 arg 等。

Important : onDismiss is 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

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.对于不熟悉 Kotlin 的人来说,这只是一个匿名接口,可以在 Java 中保存样板 iterface。 Use a field and a setter in Java.在 Java 中使用字段和设置器。

And then in onCancel然后在 onCancel

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

Have fun!玩得开心!

Kotlin Answer科特林答案

private fun showMyCustomDialog() {

    // Show.
    MyCustomDialogFragment().show(fm, "MyCustomDialogFragment")
    
    // Set pending transactions.
    fm.executePendingTransactions()
    
    // Listen dialog closing.
    MyCustomDialogFragment().dialog?.setOnDismissListener { 
        
        // You can do you job when it closed.
    }
}

Solution using kotlin and additional interface.使用 kotlin 和附加接口的解决方案。 (an example for a fragment will be shown here, but with a few changes it will work in an activity as well) (此处将显示片段的示例,但进行一些更改后,它也可以在活动中工作)

First you need to create an interface (the set of parameters can be any):首先你需要创建一个接口(参数集可以是任意的):

interface DialogCloseListener {
    fun handleDialogClose(dialog: DialogInterface)
}

Then implement this interface in the fragment that calls the DailogFragment:然后在调用 DailogFragment 的 Fragment 中实现这个接口:

class YourParentFragment: Fragment(), DialogCloseListener {
override fun handleDialogClose(dialog: DialogInterface) {
// do something
}
}

Now go to your DialogFragment.现在转到您的 DialogFragment。 Implement the onDismiss method.实现 onDismiss 方法。 In it, check if the parent fragment implements your interface, call your method, passing the necessary parameters there:在其中,检查父片段是否实现了您的接口,调用您的方法,并在那里传递必要的参数:

    override fun onDismiss(dialog: DialogInterface) {
        super.onDismiss(dialog)
        if(parentFragment is DialogCloseListener){
            (parentFragment as DialogCloseListener).handleDialogClose(dialog)
        }
    }

I think that this way is good because you can track a specific close event (by passing a certain parameter to the method), for example, canceling an order, and somehow handle it.我认为这种方式很好,因为您可以跟踪特定的关闭事件(通过将某个参数传递给方法),例如取消订单,并以某种方式处理它。

Try this尝试这个

 dialog.setOnDismissListener { Log.e("example","example") }

Have Fun!玩得开心!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM