web-dev-qa-db-ja.com

DialogFragmentでAlertDialogのカスタムビューを膨らませる問題

DialogFragmentのカスタムビューを使用してAlertDialogを作成しようとしています。このビューは、xmlから拡張する必要があります。私のDialogFragmentクラスには:

_@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new AlertDialog.Builder(getActivity())
        .setTitle("Title")
        .setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, null))
        .setPositiveButton(Android.R.string.ok, this)
        .setNegativeButton(Android.R.string.cancel, null)
        .create();
}
_

私は.setView()のために他のインフレーション方法を試しました:

_.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, (ViewGroup) getView(), false))
_

そして

_.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, (ViewGroup) getTargetFragment().getView(), false))
_

このダイアログを表示しているフラグメントにターゲットフラグメントを設定した後。

これらのすべてのカスタムビューを膨らまそうとすると、次の例外が発生します。

_E/AndroidRuntime(32352): Android.util.AndroidRuntimeException: requestFeature() must be called before adding content
E/AndroidRuntime(32352):        at com.Android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.Java:214)
E/AndroidRuntime(32352):        at com.Android.internal.app.AlertController.installContent(AlertController.Java:248)
E/AndroidRuntime(32352):        at Android.app.AlertDialog.onCreate(AlertDialog.Java:314)
E/AndroidRuntime(32352):        at Android.app.Dialog.dispatchOnCreate(Dialog.Java:335)
E/AndroidRuntime(32352):        at Android.app.Dialog.show(Dialog.Java:248)
E/AndroidRuntime(32352):        at Android.support.v4.app.DialogFragment.onStart(DialogFragment.Java:339)
E/AndroidRuntime(32352):        at Android.support.v4.app.Fragment.performStart(Fragment.Java:1288)
E/AndroidRuntime(32352):        at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:873)
E/AndroidRuntime(32352):        at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1041)
E/AndroidRuntime(32352):        at Android.support.v4.app.BackStackRecord.run(BackStackRecord.Java:625)
E/AndroidRuntime(32352):        at Android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.Java:1360)
E/AndroidRuntime(32352):        at Android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.Java:411)
E/AndroidRuntime(32352):        at Android.os.Handler.handleCallback(Handler.Java:587)
E/AndroidRuntime(32352):        at Android.os.Handler.dispatchMessage(Handler.Java:92)
E/AndroidRuntime(32352):        at Android.os.Looper.loop(Looper.Java:132)
E/AndroidRuntime(32352):        at Android.app.ActivityThread.main(ActivityThread.Java:4028)
E/AndroidRuntime(32352):        at Java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(32352):        at Java.lang.reflect.Method.invoke(Method.Java:491)
E/AndroidRuntime(32352):        at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:844)
E/AndroidRuntime(32352):        at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:602)
E/AndroidRuntime(32352):        at dalvik.system.NativeStart.main(Native Method)
_

一方、次のようにDialogFragmentgetLayoutInflator(Bundle)を使用しようとすると:

_.setView(getLayoutInflater(savedInstanceState).inflate(R.layout.dialog, null))
_

StackOverflowErrorを取得します。

AlertDialog内のDialogFragmentのカスタムビューをインフレートする方法を知っている人はいますか?

47
ashughes

最初のエラー行には、ダイアログ自体ではなく、ダイアログの作成方法に関連しているというヒントがあります。

ダイアログを自動的に作成していますか(これは、ビューがすべて設定される前に呼び出されることを意味する可能性があります)、またはボタンのクリックに応答してですか?インスタンス化の順序が原因で、最初はフラグメントに問題がありました。

同じコードを使用してビューを設定しましたが、結果は機能します。私はこれをよりきれいに見せるために他のセットアップを切り取りましたが、それを使用してもしなくても動作します。

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

    View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_layout, null);
    builder.setView(view);

    return builder.create();
}
88

それらのどれも問題を解決しないので、これらの答えに驚いています。

DialogFragmentを使用すると、同じUIをダイアログと、アプリとしてフラグメントに統合された他の場所の両方で再利用できます。非常に便利な機能。 Googleのドキュメントに従って、onCreateDialogとonCreateViewをオーバーライドすることでこれを実現できます。 http://developer.Android.com/reference/Android/app/DialogFragment.html

ここには3つのシナリオがあります。

  1. OnCreateDialogのみオーバーライド-ダイアログとして機能しますが、他の場所に統合することはできません。
  2. OnCreateViewのみをオーバーライド-ダイアログとして機能しませんが、他の場所に統合できます。
  3. 両方をオーバーライド-ダイアログとして機能し、他の場所に統合できます。

解決策:AlertDialogクラスは、requestFeatureを呼び出す別のクラスを呼び出しています。これを修正するには.. AlertDialogを使用しないで、代わりにプレーンなDialogまたはsuper.onCreateDialogが返すものを使用します。これが私が見つけた解決策が最も効果的です。

警告:DatePickerDialog、ProgressDialog、TimePickerDialogなどの他のダイアログはすべてAlertDialogを継承し、同じエラーが発生する可能性があります。

結論:DialogFragmentは、いくつかの場所で使用する必要がある非常にカスタマイズされたインターフェイスを作成する必要がある場合に適しています。既存のAndroidダイアログを再利用するように機能していないようです。

23
vangorra

要求機能のクラッシュを避け、同じレイアウトを使用します。

public class MyCombinedFragment extends DialogFragment
{
    private boolean isModal = false;

    public static MyCombinedFragment newInstance()
    {
        MyCombinedFragment frag = new MyCombinedFragment();
        frag.isModal = true; // WHEN FRAGMENT IS CALLED AS A DIALOG SET FLAG
        return frag;
    }

    public MyCombinedFragment()
    {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    {
        if(isModal) // AVOID REQUEST FEATURE CRASH
        {
        return super.onCreateView(inflater, container, savedInstanceState);
        }
        else
        {
        View view = inflater.inflate(R.layout.fragment_layout, container, false);
        setupUI(view);
        return view;
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState)
    {
        AlertDialog.Builder alertDialogBuilder = null;
        alertDialogBuilder = new AlertDialog.Builder(getActivity());
        View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_layout, null);
        alertDialogBuilder.setView(view);
        alertDialogBuilder.setTitle(“Modal Dialog“);
        alertDialogBuilder.setPositiveButton("Cancel", new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                dialog.dismiss();
            }
        });
        setupUI(view);
        return alertDialogBuilder.create();
    }
}
11

同じ問題がありました。私の場合、Android StudioはonCreateDialogで作成されたビューを返すのではなく、新しいビューを再インフレートするテンプレートonCreateViewを作成しました。onCreateDialogはonCreateDialogの後に呼び出されます。フラグメントビュー。

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    return this.getView();
}
2
seiterm

同じ問題に直面し、エラーを取り除くのに多くの時間がかかりました。最後にリソースIDをsetView()メソッドに渡すことで問題が解決しました。以下のようにセットビューを追加します。

.setView(R.layout.dialog)

1
Vinayak Bhat

同じ問題を解決するのに長い時間が必要だったので(簡単なテキストダイアログを開く)、ソリューションを共有することにしました。

Layoutfile connectivity_dialog.xmlには、メッセージテキストを含む単純なTextViewが含まれています。

<?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:gravity="center"
              Android:layout_gravity="center">
    <TextView
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_marginStart="20dp"
        Android:layout_marginEnd="20dp"
        Android:layout_marginTop="20dp"
        Android:layout_marginBottom="20dp"
        Android:text="Connectivity was lost"
        Android:textSize="34sp"
        Android:gravity="center"
        />
</RelativeLayout>

「ダイアログ」を示すアクティビティは、内部クラスを実装します(DialogFragmentはダイアログではなくフラグメントであるため、詳細は https://stackoverflow.com/a/5607560/6355541 を参照)。アクティビティは、2つの関数を介してDialogFragmentをアクティブ化および非アクティブ化できます。 Android.support.v4を使用している場合は、getSupportFragmentManager()に変更できます。

public static class ConnDialogFragment extends DialogFragment {
    public static ConnDialogFragment newInstance() {
        ConnDialogFragment cdf = new ConnDialogFragment();
        cdf.setRetainInstance(true);
        cdf.setCancelable(false);
        return cdf;
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.connectivity, container, false);
    }
}

private void dismissConn() {
    DialogFragment df = (DialogFragment) getFragmentManager().findFragmentByTag("conn");
    if (df != null) df.dismiss();
}

private void showConn() {
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment prev = getFragmentManager().findFragmentByTag("conn");
    if (prev != null) ft.remove(prev);
    ft.addToBackStack(null);
    ConnDialogFragment cdf = ConnDialogFragment.newInstance();
    cdf.show(ft, "conn");
}
0
vasquez

私はXMLを膨らませていませんが、DialogFragmentで動的ビュー生成を正常に完了しました。

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    m_editText = new EditText(getActivity());
    return new AlertDialog.Builder(getActivity())
            .setView(m_editText)
            .setPositiveButton(Android.R.string.ok,null)
            .setNegativeButton(Android.R.string.cancel, null);
            .create();
}
0
Shinyosan

呼び出すコードで

 create().

と置換する

show().
0

代わりに行うことは、通常どおりonCreateViewメソッドでカスタムビューを作成することです。ダイアログのタイトルを変更するようなことをしたい場合は、onCreateViewで行います。

ここに私が意味することを説明する例があります:

        @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        getDialog().setTitle("hai");
        View v = inflater.inflate(R.layout.fragment_dialog, container, false);
        return v;
    }

それからあなたは電話するだけです:

DialogFragment df = new MyDialogFragment();
df.show(..);

出来上がり、独自のカスタムビューを持つダイアログ。

0
stork