web-dev-qa-db-fra.com

Problème lors du gonflage de l'affichage personnalisé pour AlertDialog dans DialogFragment

J'essaie de créer un DialogFragment en utilisant une vue personnalisée dans un AlertDialog. Cette vue doit être gonflée à partir de xml. Dans ma classe DialogFragment, j'ai:

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

J'ai essayé d'autres méthodes de gonflage pour .setView() telles que:

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

et

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

Après avoir défini le fragment cible dans le fragment qui affiche cette boîte de dialogue.

Toutes ces tentatives pour gonfler ma vue personnalisée entraînent l'exception suivante:

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)

Tandis que si j'essaie d'utiliser le DialogFragment 's getLayoutInflator(Bundle) comme ceci:

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

Je reçois un StackOverflowError.

Est-ce que quelqu'un sait comment gonfler une vue personnalisée pour un AlertDialog dans un DialogFragment?

43
ashughes

La première ligne d'erreur m'indique que cela est lié à la façon dont vous créez votre dialogue - pas au dialogue lui-même.

Créez-vous la boîte de dialogue automatiquement (ce qui pourrait signifier que cette option est appelée avant que toutes les vues soient configurées) ou en réponse à un clic de bouton? J'ai d'abord eu des problèmes avec les fragments en raison de l'ordre d'instanciation.

J'ai utilisé le même code pour définir la vue que vous avez, et mon résultat fonctionne. J'ai coupé l'autre configuration pour rendre ce look plus propre, mais cela fonctionne avec ou sans.

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

Je suis surpris par ces réponses car aucune d’entre elles ne résout le problème.

Un DialogFragment vous permet de réutiliser la même interface utilisateur à la fois pour un dialogue et de l'intégrer à votre application ailleurs en tant que fragment. Une fonctionnalité très utile. Selon la documentation de Google, vous pouvez y parvenir en remplaçant onCreateDialog et onCreateView . http://developer.Android.com/reference/Android/app/DialogFragment.html

Il y a trois scénarios ici:

  1. Remplacer uniquement onCreateDialog - Fonctionne comme un dialogue mais ne peut pas être intégré ailleurs.
  2. Remplacer uniquement surCreateView - Ne fonctionne pas comme un dialogue mais peut être intégré ailleurs.
  3. Remplacer les deux - Fonctionne comme un dialogue et peut être intégré ailleurs.

Solution: La classe AlertDialog appelle une autre classe qui appelle requestFeature. Pour résoudre ce problème .. N'utilisez pas AlertDialog, utilisez plutôt un dialogue en clair ou tout autre retour de super.onCreateDialog. C'est la solution que j'ai trouvée qui fonctionne le mieux.

Avertissement: D'autres boîtes de dialogue telles que DatePickerDialog, ProgressDialog, TimePickerDialog héritent toutes de AlertDialog et provoqueront probablement la même erreur.

Bottom Line: DialogFragment est utile si vous devez créer une interface très personnalisée qui doit être utilisée à plusieurs endroits. Il ne semble pas fonctionner pour réutiliser les dialogues Android existants.

22
vangorra

Evitez le crash de la fonctionnalité de demande et utilisez la même présentation:

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
SolarDriftSolutions

J'ai eu le même problème. Dans mon cas, c'est parce qu'Android Studio a créé un modèle onCreateView qui a regonflé une nouvelle vue au lieu de renvoyer la vue créée dans onCreateDialog. onCreateView étant appelé après onCreateDialog, la solution consistait simplement à rétablir la vue des fragments.

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

Comme j'avais besoin de beaucoup de temps pour résoudre le même problème (Ouvrir une boîte de dialogue texte simple), j'ai décidé de partager ma solution:

Le fichier de configuration connectivity_dialog.xml contient un simple TextView avec le texte du message:

<?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>

L'activité affichant le "dialogue" implémente une classe interne (DialogFragment étant un fragment et non un dialogue; pour plus d'informations, voir https://stackoverflow.com/a/5607560/6355541 ). L'activité peut activer et désactiver le DialogFragment via deux fonctions. Si vous utilisez Android.support.v4, vous souhaiterez peut-être utiliser 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

Je n'ai pas gonflé à partir de XML mais j'ai réussi à générer une vue dynamique dans un 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

Dans votre code où vous appelez 

 create().

Remplacer par

show().
0
coder_For_Life22

Au lieu de cela, vous souhaitez créer votre vue personnalisée dans la méthode onCreateView comme vous le feriez normalement. Si vous voulez faire quelque chose comme changer le titre de la boîte de dialogue, faites-le dans onCreateView.

Voici un exemple pour illustrer ce que je veux dire:

        @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;
    }

Ensuite, vous appelez simplement:

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

Et voila, un dialogue avec votre propre vue personnalisée.

0
stork