web-dev-qa-db-fra.com

ViewPager dans DialogFragment - IllegalStateException: Fragment n'a pas de vue.

Ce que je veux réaliser

  • Depuis une FragmentActivity, affichez une boîte de dialogue lorsque vous cliquez sur un bouton d'action dans la barre d'action.
  • DialogFragment - Un dialogue sans titre
  • TabHost - Onglets en haut de la boîte de dialogue
  • ViewPager avec FragmentPagerAdapter - Balayable, quel contenu est connecté aux onglets
  • 2-3 Boutons de dialogue (différentes sous-classes du dialogue, différents boutons) - Ne sont pas censés figurer dans l’un des ViewPager's Fragment, ce qui signifie que les mêmes boutons doivent rester au bas du dialogue, indépendamment de ce que Fragment est affiché par le ViewPager.


Le problème

IllegalStateException: Fragment does not have a view


Ce que j'ai essayé/fait jusqu'à présent

  • Utilisation du package Android.support.v4 pour les classes nécessaires
  • Appel de getChildFragmentManager() au lieu de getSupportedFragmentManager()
  • Mise en œuvre du message n ° 10 suggéré à partir de ce lienhttps://code.google.com/p/Android/issues/detail?id=42601. Je copie/colle le code directement dans mes deux classes Fragment, que la ViewPager est censée montrer, plus la classe DialogFragment.
  • Dans ma coutume DialogFragment, j'ai d'abord essayé de remplacer onCreateView, puis onCreateDialog et les deux en même temps. Tout ce que je dois courir mais avec des résultats inattendus.
    • Seulement onCreateView: Impossible d'atteindre le AlertDialog.Builder pour créer les boutons nécessaires, à part le fait que les résultats du dialogue étaient excellents.
    • onCreateDialog uniquement: le message d'erreur indiqué ci-dessus. J'imagine toujours que cette méthode est aussi proche que possible de ce que je veux réaliser.
    • onCreateView et onCreateDialog: Gonfle la disposition de dialogue dans onCreateView et ajoute les boutons de dialogue au AlertDialog.Builder dans onCreateDialog. Cela affiche la boîte de dialogue, mais les boutons ajoutés à partir du AlertDialog.Builder ne sont pas visibles. De plus, le clavier ne s'affiche pas lorsque vous cliquez sur un champ EditText.


Code source

La plupart proviennent deDidacticiel pour implémenter l'utilisation de TabHost dans Android 2.2 + ViewPager et Fragments. Le code de la ActivityFragment est plutôt dans une DialogFragment. Cependant, j'ai remplacé son ViewPager par un code modifié à partir du code source de cette réponsehttps://stackoverflow.com/a/18167273/2375978. C'était pour pouvoir wrap_content en hauteur.

Le code défectueux dans mon projet est dans la méthode DialogFragment de onCreateDialog, je crois.

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), AlertDialog.THEME_HOLO_DARK);
    LayoutInflater inflater = getActivity().getLayoutInflater();
    view = inflater.inflate(R.layout.dialog_test, null);
    addActionButtons(builder, view);    
    builder.setView(view);

    mViewPager = (WrapContentHeightViewPager) view.findViewById(R.id.viewpager);

    initialiseTabHost();

    List<Fragment> fragments = getFragments();

    pageAdapter = new DialogPageAdapter(getChildFragmentManager(), fragments);
    mViewPager.setAdapter(pageAdapter);
    mViewPager.setOnPageChangeListener(this);

    Dialog dialog = builder.create();
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
    dialog.show();

    return dialog;
}


Journal de trace de pile LogCat

FATAL EXCEPTION: main
Java.lang.IllegalStateException: Fragment does not have a view
    at Android.support.v4.app.Fragment$1.findViewById(Fragment.Java:1425)
    at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:901)
    at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1088)
    at Android.support.v4.app.BackStackRecord.run(BackStackRecord.Java:682)
    at Android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.Java:1444)
    at Android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.Java:461)
    at Android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.Java:141)
    at Android.support.v4.view.ViewPager.populate(ViewPager.Java:1011)
    at Android.support.v4.view.ViewPager.populate(ViewPager.Java:880)
    at Android.support.v4.view.ViewPager.onMeasure(ViewPager.Java:1374)
    at my.app.package.name.WrapContentHeightViewPager.onMeasure(WrapContentHeightViewPager.Java:31)
    at Android.view.View.measure(View.Java:15481)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5059)
    at Android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.Java:1396)
    at Android.widget.LinearLayout.measureVertical(LinearLayout.Java:681)
    at Android.widget.LinearLayout.onMeasure(LinearLayout.Java:574)
    at Android.view.View.measure(View.Java:15481)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5059)
    at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:310)
    at Android.view.View.measure(View.Java:15481)
    at Android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.Java:617)
    at Android.widget.RelativeLayout.onMeasure(RelativeLayout.Java:399)
    at Android.view.View.measure(View.Java:15481)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5059)
    at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:310)
    at Android.view.View.measure(View.Java:15481)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5059)
    at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:310)
    at Android.view.View.measure(View.Java:15481)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5059)
    at Android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.Java:1396)
    at Android.widget.LinearLayout.measureVertical(LinearLayout.Java:681)
    at Android.widget.LinearLayout.onMeasure(LinearLayout.Java:574)
    at Android.view.View.measure(View.Java:15481)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5059)
    at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:310)
    at Android.view.View.measure(View.Java:15481)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5059)
    at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:310)
    at Android.view.View.measure(View.Java:15481)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5059)
    at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:310)
    at com.Android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.Java:2377)
    at Android.view.View.measure(View.Java:15481)
    at Android.view.ViewRootImpl.performMeasure(ViewRootImpl.Java:1982)
    at Android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.Java:1200)
    at Android.view.ViewRootImpl.performTraversals(ViewRootImpl.Java:1398)
    at Android.view.ViewRootImpl.doTraversal(ViewRootImpl.Java:1118)
    at Android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.Java:4525)
    at Android.view.Choreographer$CallbackRecord.run(Choreographer.Java:725)
    at Android.view.Choreographer.doCallbacks(Choreographer.Java:555)
    at Android.view.Choreographer.doFrame(Choreographer.Java:525)
    at Android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.Java:711)
    at Android.os.Handler.handleCallback(Handler.Java:615)
    at Android.os.Handler.dispatchMessage(Handler.Java:92)
    at Android.os.Looper.loop(Looper.Java:137)
    at Android.app.ActivityThread.main(ActivityThread.Java:4946)
    at Java.lang.reflect.Method.invokeNative(Native Method)
    at Java.lang.reflect.Method.invoke(Method.jav


Également...

  • J'ai pu sans succès essayer l'autre solution possible mentionnée dans https://code.google.com/p/Android/issues/detail?id=42601 , mentionnée dans les posts n ° 2 et n ° 13, car je Je n'ai pas compris comment et où je peux l'utiliser dans mon code (je suppose que je suis dans le même bateau que la personne qui a écrit # 18).
25
Henrik Wassdahl

Je pense avoir rencontré le même problème et appris quelques choses en consultant la source de DialogFragment .

Il semble que, bien que surcharger onCreateDialog (...) soit un moyen valide de créer une boîte de dialogue personnalisée, cela aura pour résultat que DialogFragment aura une vue null, tout comme le message d'erreur le dit. Dans la plupart des cas, cela convient: le DialogFragment n'a pas besoin d'une vue pour afficher un dialogue, mais si vous souhaitez imbriquer des fragments plus loin (comme vous le faites), celui-ci ne volera pas.

Étant donné que vous souhaitez interagir avec AlertDialog.Builder, il n’existe pas de solution parfaite à ma connaissance, mais vous disposez de quelques options:

  1. Créez les boutons dans votre boîte de dialogue dans le cadre de la vue (sans utiliser AlertDialog.Builder). Pour ce faire, vous substituez onCreateView à la place de onCreateDialog. Vous devriez pouvoir obtenir la fonctionnalité que vous mentionnez en plaçant les boutons dans leur propre fragment. Nous faisons quelque chose de similaire lors de mon concert et je préfère de loin cette méthode.
  2. Implémentez votre propre type qui hérite de Fragment et qui reflète le DialogFragment dans tous les sens, sauf permettre ce dont vous avez besoin. Cela ne devrait pas être trop effrayant car DialogFragment est seulement ~ 400 et est fortement commenté. Pourrait être amusant.
  3. Utilisez un PagerAdapter standard au lieu d'un FragmentPagerAdapter. De cette façon, votre DialogFragment n'aura pas de vue.
35
Tommy Visic

Utilisez le 

onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)

au lieu de onCreateDialog (Bundle savedInstanceState). Ne créez pas de boîte de dialogue d'alerte, utilisez le gonfleur fourni par la méthode et créez votre vue. Ça marche pour moi.

Meilleures salutations!

20
Skycorsarius

Merci à @Tommy Visic pour avoir écrit une très bonne description, cela a fonctionné.

Afficher le code qui a fonctionné pour moi.

J'ai supprimé le code du bâtiment Dialog de la méthode onCreateDialog. En fait, la méthode onCreateDialog supprimée et la vue de dialogue que j'ai implémentée dans la vue personnalisée Dialog's je l'ai inclus en tant que View dans la méthode onCreateView et toutes les choses qui ont commencé à fonctionner.

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.login_sigup_screen, null, false);
    bind = ButterKnife.bind(this, view);
    initViewPager();
    return view;
}

Face à un autre problème avec cette mise en œuvre est:

Quand une Activity a Toolbar/ActionBar, elle est également affichée dans la DialogFragment pour éviter que ce qui doit être fait soit: Implémente la méthode onViewCreated de Fragment et ajoute le code ci-dessous.

Dialog dialog = getDialog();
dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
float dimAmount = 0.6f;
dialog.getWindow().setDimAmount(dimAmount);

Cela supprimera la Toolbar de la DialogFragment et Activity sera affiché tel quel.

À votre santé

Merci @Tommy

Cordialement Zeus

2

Si vous implémentez onCreateDialog pour utiliser AlertDialog, vous rencontrerez IllegalStateException: Fragment does not have a view lorsque vous accéderez à getChildFragmentManager ou quelque chose d'équivalent.

Pour résoudre ce problème, implémentez onCreateDialog et onCreateView, où onCreateView renvoie la vue gonflée dans onCreateDialog.

class LocationPickerDialog : DialogFragment() {

    lateinit var customView: View

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return customView
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        Log.d(TAG, "onCreateDialog")
        // StackOverflowError
        // customView = layoutInflater.inflate(R.layout.dialog_location_picker, null)
        customView = activity!!.layoutInflater.inflate(R.layout.dialog_location_picker, null)

        val builder = AlertDialog.Builder(context!!)
                .setView(customView)
                .setPositiveButton(Android.R.string.ok) { _, _ ->
                    // do something
                }
                .setNegativeButton(Android.R.string.cancel) { _, _ ->
                    // do something
                }
        val dialog = builder.create()

        return dialog
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        // if onCreateView doesn't return a view 
        // Java.lang.IllegalStateException: Fragment does not have a view
        mapFragment = childFragmentManager.findFragmentByTag("map") as SupportMapFragment?
    }
}

https://code.luasoftware.com/tutorials/Android/android-alertdialog-in-dialogfragment-fragment-does-not-haot-a-view/

0
Desmond Lua