从片段显示对话框?

Posted

技术标签:

【中文标题】从片段显示对话框?【英文标题】:Show dialog from fragment? 【发布时间】:2011-07-20 13:48:33 【问题描述】:

我有一些需要显示常规对话框的片段。在这些对话框中,用户可以选择是/否的答案,然后片段应该做出相应的行为。

现在,Fragment 类没有要覆盖的onCreateDialog() 方法,所以我想我必须在包含Activity 的外部实现对话框。没关系,但是Activity 需要以某种方式将所选答案报告给片段。我当然可以在这里使用回调模式,因此片段在Activity 上注册一个监听器类,Activity 会通过那个或类似的东西报告答案。

但这对于在片段中显示“简单”是-否对话框的简单任务来说似乎是一个很大的混乱。此外,这样我的Fragment 将不那么独立。

有更简洁的方法吗?

编辑:

这个问题的答案并没有真正详细解释应该如何使用 DialogFragments 来显示来自 Fragments 的对话框。所以AFAIK,要走的路是:

    显示片段。 在需要时,实例化一个 DialogFragment。 将原来的Fragment设置为这个DialogFragment的目标,用.setTargetFragment()。 使用原始片段中的 .show() 显示 DialogFragment。 当用户在此 DialogFragment 上选择某个选项时,通知原始 Fragment 有关此选择(例如用户单击“是”),您可以使用 .getTarget() 获取原始 Fragment 的引用。 关闭 DialogFragment。

【问题讨论】:

您的技术有效,除非发生屏幕旋转。然后我得到一个力量。有什么想法吗? @Weston 查看 Zsombor 的第一个答案:***.com/questions/8235080/… 【参考方案1】:

我必须谨慎地怀疑以前接受的答案,即使用 DialogFragment 是最佳选择。 DialogFragment 的预期(主要)目的似乎是显示 对话框本身的片段,而不是显示 个对话框要显示的片段。

我相信使用片段的活动在对话和片段之间进行调解是更好的选择。

【讨论】:

由于托管对话框 (onCreateDialog) 方法即将被弃用,我不同意并说DialogFragment 确实是要走的路。 接受的答案意味着使用 DialogFragment 而不是 Dialog,而不是 ListFragment,AFAICS。 @anoniim 这取决于对话片段的使用方式。如果将其用作常规片段,则很好。如果它被用作对话框,那么是的,你不应该显示另一个对话框。 @anoniim 只要启动片段不是对话框,就可以。我不确定 ChildFragmentManager,我使用了 SupportFragmentManager,效果很好。这一切都在文档中。 这个答案在各个层面上都非常适合我。【参考方案2】:

您应该改用DialogFragment。

【讨论】:

不幸的是,这种方法比以前 android 版本的经典托管对话框方法更冗长,但它现在是首选方法。您可以通过使用FragmentManagerputFragmentgetFragment 方法完全避免引用Activity,从而允许DialogFragment 直接向调用片段报告(即使在方向更改之后)。 如果你有一个 ListFragment 需要显示 Dialogs,不能同时扩展它们怎么办 ListFragment 子类将通过实例化新的 DialogFragment 来使用 DialogFragment,而不是通过子类化 DialogFragment。 (DialogFragment 是一个实现为 Fragment 的对话框,而不是可以显示 Dialogs 的 Fragment。) 请加一些sn-p,方便我们理解【参考方案3】:

这是一个是/否 DialogFragment 的完整示例:

班级:

public class SomeDialog extends DialogFragment 

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) 
        return new AlertDialog.Builder(getActivity())
            .setTitle("Title")
            .setMessage("Sure you wanna do this!")
            .setNegativeButton(android.R.string.no, new OnClickListener() 
                @Override
                public void onClick(DialogInterface dialog, int which) 
                    // do nothing (will close dialog)
                
            )
            .setPositiveButton(android.R.string.yes,  new OnClickListener() 
                @Override
                public void onClick(DialogInterface dialog, int which) 
                    // do something
                
            )
            .create();
    

开始对话:

        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        // Create and show the dialog.
        SomeDialog newFragment = new SomeDialog ();
        newFragment.show(ft, "dialog");

您也可以让类实现 onClickListener 并使用它来代替嵌入式侦听器。

活动回调

如果你想实现回调,这就是它的完成方式 在您的活动中:

YourActivity extends Activity implements OnFragmentClickListener

@Override
public void onFragmentClick(int action, Object object) 
    switch(action) 
        case SOME_ACTION:
        //Do your action here
        break;
    

回调类:

public interface OnFragmentClickListener 
    public void onFragmentClick(int action, Object object);

然后要从片段执行回调,您需要确保侦听器是这样附加的:

@Override
public void onAttach(Activity activity) 
    super.onAttach(activity);
    try 
        mListener = (OnFragmentClickListener) activity;
     catch (ClassCastException e) 
        throw new ClassCastException(activity.toString() + " must implement listeners!");
    

并且回调是这样执行的:

mListener.onFragmentClick(SOME_ACTION, null); // null or some important object as second parameter.

【讨论】:

这里不解释如何从 Fragment 启动它 @raveN 您只需对您的活动进行回调即可启动片段。 @Warpzit 感谢您的全面回答。我害怕触摸 FragmentManager,我已经在用它做不虔诚的事情了......我如何将 onClick 事件传递回需要用户输入的(非对话框)片段?顺便说一句,交易不应该添加到后台吗? @kaay 从活动中您可以调用给定片段中需要新输入的任何公共方法。从那里可以很容易地使用新内容进行更新。 @RichardLeMesurier 确实,片段有起有落。【参考方案4】:

对我来说,是这样的——

我的片段:

public class MyFragment extends Fragment implements MyDialog.Callback

    ShowDialog activity_showDialog;

    @Override
    public void onAttach(Activity activity)
    
        super.onAttach(activity);
        try
        
            activity_showDialog = (ShowDialog)activity;
        
        catch(ClassCastException e)
        
            Log.e(this.getClass().getSimpleName(), "ShowDialog interface needs to be     implemented by Activity.", e);
            throw e;
        
    

    @Override
    public void onClick(View view) 
    
        ...
        MyDialog dialog = new MyDialog();
        dialog.setTargetFragment(this, 1); //request code
        activity_showDialog.showDialog(dialog);
        ...
    

    @Override
    public void accept()
    
        //accept
    

    @Override
    public void decline()
    
        //decline
    

    @Override
    public void cancel()
    
        //cancel
    


我的对话:

public class MyDialog extends DialogFragment implements View.OnClickListener

    private EditText mEditText;
    private Button acceptButton;
    private Button rejectButton;
    private Button cancelButton;

    public static interface Callback
    
        public void accept();
        public void decline();
        public void cancel();
    

    public MyDialog()
    
        // Empty constructor required for DialogFragment
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    
        View view = inflater.inflate(R.layout.dialogfragment, container);
        acceptButton = (Button) view.findViewById(R.id.dialogfragment_acceptbtn);
        rejectButton = (Button) view.findViewById(R.id.dialogfragment_rejectbtn);
        cancelButton = (Button) view.findViewById(R.id.dialogfragment_cancelbtn);
        acceptButton.setOnClickListener(this);
        rejectButton.setOnClickListener(this);
        cancelButton.setOnClickListener(this);
        getDialog().setTitle(R.string.dialog_title);
        return view;
    

    @Override
    public void onClick(View v)
    
        Callback callback = null;
        try
        
            callback = (Callback) getTargetFragment();
        
        catch (ClassCastException e)
        
            Log.e(this.getClass().getSimpleName(), "Callback of this class must be implemented by target fragment!", e);
            throw e;
        

        if (callback != null)
        
            if (v == acceptButton)
               
                callback.accept();
                this.dismiss();
            
            else if (v == rejectButton)
            
                callback.decline();
                this.dismiss();
            
            else if (v == cancelButton)
            
                callback.cancel();
                this.dismiss();
            
        
    

活动:

public class MyActivity extends ActionBarActivity implements ShowDialog

    ..

    @Override
    public void showDialog(DialogFragment dialogFragment)
    
        FragmentManager fragmentManager = getSupportFragmentManager();
        dialogFragment.show(fragmentManager, "dialog");
    

DialogFragment 布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:layout_gravity="center"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/dialogfragment_textview"
        android:layout_
        android:layout_
        android:layout_marginTop="20dp"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="10dp"
        android:text="@string/example"/>

    <Button
        android:id="@+id/dialogfragment_acceptbtn"
        android:layout_
        android:layout_
        android:layout_marginTop="20dp"
        android:layout_centerHorizontal="true"
        android:layout_below="@+id/dialogfragment_textview"
        android:text="@string/accept"
        />

    <Button
        android:id="@+id/dialogfragment_rejectbtn"
        android:layout_
        android:layout_
        android:layout_marginTop="10dp"
        android:layout_alignLeft="@+id/dialogfragment_acceptbtn"
        android:layout_below="@+id/dialogfragment_acceptbtn"
        android:text="@string/decline" />

     <Button
        android:id="@+id/dialogfragment_cancelbtn"
        android:layout_
        android:layout_
        android:layout_marginTop="10dp"
        android:layout_marginBottom="20dp"
        android:layout_alignLeft="@+id/dialogfragment_rejectbtn"
        android:layout_below="@+id/dialogfragment_rejectbtn"
        android:text="@string/cancel" />

     <Button
        android:id="@+id/dialogfragment_heightfixhiddenbtn"
        android:layout_
        android:layout_
        android:layout_marginTop="10dp"
        android:layout_marginBottom="20dp"
        android:layout_alignLeft="@+id/dialogfragment_cancelbtn"
        android:layout_below="@+id/dialogfragment_cancelbtn"
        android:background="@android:color/transparent"
        android:enabled="false"
        android:text=" " />
</RelativeLayout>

正如名称dialogfragment_heightfixhiddenbtn 所示,尽管说wrap_content,但我无法解决底部按钮的高度被减半的问题,所以我添加了一个隐藏按钮以“减半”反而。很抱歉被黑了。

【讨论】:

+1 使用setTargetFragment() 的引用集在旋转后重新启动活动/片段集时由系统正确重新创建。所以引用会自动指向新的目标。 我现在要打自己的鼻子,因为以前没有使用 ButterKnife。使用 ButterKnife,它会让你的视图处理更漂亮。 您可以使用Otto将事件从Fragment发送到Activity,这样您就不需要接口附加魔术了。 Otto 示例:***.com/a/28480952/2413303 @EpicPandaForce 请您添加“ShowDialog”接口/类吗?这是您的示例中唯一缺少的内容。 @ntrch 它是public interface ShowDialog void showDialog(DialogFragment dialogFragment); 【参考方案5】:
 public void showAlert()


     AlertDialog.Builder alertDialog = new AlertDialog.Builder(getActivity());
     LayoutInflater inflater = getActivity().getLayoutInflater();
     View alertDialogView = inflater.inflate(R.layout.test_dialog, null);
     alertDialog.setView(alertDialogView);

     TextView textDialog = (TextView) alertDialogView.findViewById(R.id.text_testDialogMsg);
     textDialog.setText(questionMissing);

     alertDialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() 
         public void onClick(DialogInterface dialog, int which) 
             dialog.cancel();
         
     );
     alertDialog.show();


.test_dialog 是 xml 自定义的地方

【讨论】:

【参考方案6】:

我自己也是一个初学者,老实说,我找不到一个我能理解或实施的令人满意的答案。

所以这里有一个外部链接,它确实帮助我实现了我想要的。它非常简单明了,也很容易理解。

http://www.helloandroid.com/tutorials/how-display-custom-dialog-your-android-application

这就是我试图通过代码实现的目标:

我有一个承载片段的 MainActivity。我希望在布局顶部出现一个对话框来询问用户输入,然后相应地处理输入。 See a screenshot

这是我片段的 onCreateView 的样子

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 

    View rootView = inflater.inflate(R.layout.fragment_home_activity, container, false);

    Button addTransactionBtn = rootView.findViewById(R.id.addTransactionBtn);

    addTransactionBtn.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View view) 
            Dialog dialog = new Dialog(getActivity());
            dialog.setContentView(R.layout.dialog_trans);
            dialog.setTitle("Add an Expense");
            dialog.setCancelable(true);

            dialog.show();

        
    );

希望对你有帮助

如果有任何困惑,请告诉我。 :)

【讨论】:

【参考方案7】:
    public static void OpenDialog (Activity activity, DialogFragment fragment)

    final FragmentManager fm = ((FragmentActivity)activity).getSupportFragmentManager();

    fragment.show(fm, "tag");

【讨论】:

请为您的回答添加一些解释

以上是关于从片段显示对话框?的主要内容,如果未能解决你的问题,请参考以下文章

在片段中我想点击如何显示警告对话框

执行代码时有时不显示对话框片段

如何在 BottomSheetDialogFragment 顶部显示另一个片段

从片段类中的对话框添加项目到recyclerview。

webView loadUrl 打开浏览器选择对话框

片段中的请求权限不显示对话框