フラグメントからダイアログを表示しますか?


119

通常のダイアログを表示する必要があるいくつかのフラグメントがあります。これらのダイアログで、ユーザーは「はい/いいえ」の回答を選択でき、フラグメントはそれに応じて動作するはずです。

さて、FragmentクラスにはonCreateDialog()オーバーライドするメソッドがないので、ダイアログを外側のコンテナに実装する必要があると思いますActivity。それは問題ありませんが、その場合Activity、選択された回答を何らかの形でフラグメントに報告する必要があります。もちろん、ここでコールバックパターンを使用することもできるので、フラグメントはそれ自体をActivityリスナクラスに登録し、アクティビティはそれを介して、またはそのようなもので答えを報告します。

しかし、これは、「単純な」はい/いいえのダイアログをフラグメントで表示するため、単純なタスクではかなり大きな混乱のようです。また、この方法では、Fragment自己完結性が低くなります。

これを行うためのより明確な方法はありますか?

編集:

この質問への答えは、フラグメントからのダイアログを表示するためにDialogFragmentsをどのように使用する必要があるかを詳細に説明していません。だから私の知る限り、行く方法は:

  1. フラグメントを表示します。
  2. 必要に応じて、DialogFragmentをインスタンス化します。
  3. を使用して、このDialogFragmentのターゲットとして元のFragmentを設定し.setTargetFragment()ます。
  4. 元のフラグメントの.show()でDialogFragmentを表示します。
  5. ユーザーがこのDialogFragmentでいくつかのオプションを選択し、この選択について元のFragmentに通知すると(たとえば、ユーザーが「はい」をクリックした場合)、. getTarget()を使用して元のFragmentの参照を取得できます。
  6. DialogFragmentを閉じます。

1
画面の回転が発生する場合を除いて、テクニックは機能します。そのとき私は迫力を得る。何か案は?
Weston、

:Zsomborによる最初の答えをチェックアウト@Weston stackoverflow.com/questions/8235080/...を
mightimaus

回答:


37

代わりにDialogFragmentを使用してください


9
残念ながら、このアプローチは、以前のAndroidリビジョンの従来の管理ダイアログアプローチよりも少し冗長ですが、現在では推奨される方法です。のメソッドとメソッドをActivity使用して全体を参照することを回避できます。これにより、は呼び出し方向のフラグメントに直接レポートできます(方向を変更した後でも)。putFragmentgetFragmentFragmentManagerDialogFragment
デイブ

ダイアログを表示する必要があるListFragmentがある場合、両方を拡張することはできません
marchinram

16
ListFragmentサブクラスは、DialogFragmentをサブクラス化するのではなく、新しいインスタンスをインスタンス化することによってDialogFragmentsを使用します。(DialogFragmentは、ダイアログとして表示されるフラグメントではなく、フラグメントとして実装されるダイアログです。)
nmr

4
簡単に理解できるように、スニペットを追加してください
Arpit Patel

35

私は、DialogFragmentを使用することが最良の選択肢であるという以前に受け入れられた答えを慎重に疑わなければなりません。DialogFragmentの意図された(主な)目的は、ダイアログ自体であるフラグメントを表示することであり、表示するダイアログを持つフラグメントを表示することではないようです。

フラグメントのアクティビティーを使用してダイアログとフラグメントの間を仲介することは、好ましいオプションであると思います。


10
管理されたダイアログ(onCreateDialog)のアプローチはまもなく廃止される予定ですので、私は反対し、それDialogFragmentが実際に進むべき道であると述べます。
デイブ

4
受け入れられた回答とは、ListFragment、AFAICSではなく、Dialogの代わりにDialogFragmentを使用することを意味します。
nmr

実際ダイアログ断片ダイアログと正常断片の両方として使用することができる-埋め込み参照developer.android.com/reference/android/app/DialogFragment.htmlを
クライブジェ

@CliveJefferiesできますが、それ自体から他のダイアログを表示することは想定されていません。私はここの人たちは質問を間違っていると思います。
マルセルブロ

@anoniimダイアログフラグメントがどのように使用されているかによります。通常のフラグメントとして使用する場合は問題ありません。ダイアログとして使用されている場合、はい、別のダイアログを表示するべきではありません。
Clive Jefferies 2016

24

yes / no 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.

4
これは、フラグメントから開始する方法を説明していません
akohout

@raveNあなたは単にあなたの活動にコールバックをするだけで、フラグメントを開始します。
Warpzit 2014年

@Warpzit包括的な回答ありがとうございます。FragmentManagerに触れるのは怖いです。これは、すでに不思議なことをしています...ユーザー入力を必要とする(非ダイアログ)フラグメントにonClickイベントを返すにはどうすればよいですか。ところで、トランザクションはバックスタックに追加されるべきではありませんか?
kaay 14

@kaayアクティビティから、新しい入力を必要とする特定のフラグメント内の任意のパブリックメソッドを呼び出すことができます。そこから、新しいコンテンツでの更新はかなり簡単になるはずです。
Warpzit 14

1
@RichardLeMesurier確かに、フラグメントは浮き沈みです。
Warpzit 2014

13

私にとっては、

MyFragment:

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
    }

}

MyDialog:

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_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:orientation="vertical" >

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

    <Button
        android:id="@+id/dialogfragment_acceptbtn"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        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_width="200dp"
        android:layout_height="wrap_content"
        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_width="200dp"
        android:layout_height="wrap_content"
        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_width="200dp"
        android:layout_height="20dp"
        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
+1のリファレンスセットsetTargetFragment()は、回転後にアクティビティ/フラグメントセットを再起動したときに、システムによって正しく再作成されます。したがって、参照は自動的に新しいターゲットを指します。
Richard Le Mesurier 2014

でも、当時はバターナイフを使用していなかったので、今は自分を鼻に刺すつもりです。ButterKnifeを使用すると、ビューの処理がより美しくなります。
EpicPandaForce 2014年

また、Ottoを使用してFragmentからActivityにイベントを送信できるため、インターフェース接続のマジックは必要ありません。ここのOttoの例:stackoverflow.com/a/28480952/2413303
EpicPandaForce

@EpicPandaForceどうか、「ShowDialog」インターフェース/クラスを追加できますか?それはあなたの例で欠けている唯一のものです。
ntrch 2018

@ntrchだったpublic interface ShowDialog { void showDialog(DialogFragment dialogFragment); }
EpicPandaForce

3
 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カスタム


2

私自身も初心者であり、正直に理解または実行できる満足のいく答えを見つけることができませんでした。

だからここに私が本当に望んだことを達成するのを助けた外部リンクがあります。それは非常に簡単で、フォローするのも簡単です。

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

これは私がコードを達成しようとしたものです:

フラグメントをホストするMainActivityがあります。レイアウトの上にダイアログを表示してユーザー入力を要求し、それに応じて入力を処理する必要がありました。 スクリーンショットを見る

これが私のフラグメントの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();

        }
    });

お役に立てば幸いです

混乱がある場合はお知らせください。:)


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.