72 votes

Composant de l'architecture de navigation - Fragments de dialogue

Est-il possible d'utiliser le nouveau composant d'architecture de navigation avec DialogFragment ? Dois-je créer un navigateur personnalisé ?

J'aimerais beaucoup les utiliser avec les nouvelles fonctionnalités de mon graphique de navigation.

90voto

MatPag Points 12624

Mise à jour de mai 2019 :

DialogFragment sont désormais entièrement pris en charge à partir de l'année 2010. Navigation 2.1.0 vous pouvez lire la suite aquí y aquí

Ancienne réponse pour Navigation <= 2.1.0-alpha02 :

J'ai procédé de cette façon :

1) Mise à jour Navigation bibliothèque au moins à la version 2.1.0-alpha01 et copier les deux fichiers de ce Liste modifiée dans votre projet.

2) Ensuite, dans votre fragment d'hôte de navigation, changez le name à votre projet personnalisé NavHostFragment

<fragment
    android:id="@+id/nav_host_fragment"
    android:name="com.example.app.navigation.MyNavHostFragment"
    app:defaultNavHost="true"
    app:navGraph="@navigation/nav_graph"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/toolbar" />

3) Créez votre DialogFragment et les ajouter à votre nav_graph.xml avec :

<dialog
    android:id="@+id/my_dialog"
    android:name="com.example.ui.MyDialogFragment"
    tools:layout="@layout/my_dialog" />

4) Maintenant, lancez-les à partir des fragments ou de l'activité avec

findNavController().navigate(R.id.my_dialog)

ou des méthodes similaires.

1 votes

J'ai essayé avec la dernière version et cela fonctionne mais les animations ne fonctionnent pas pour moi. Je dois les définir dans la classe de dialogue. Est-ce que cela arrive à quelqu'un aussi ?

23 votes

Comment traiter son auditeur de clics positifs et négatifs.

1 votes

@Pinakin vous manipulez les résultats directement dans votre personnalisé DialogFragment par exemple en utilisant le onCreateDialog et de fixer un setPositiveButton y setNegativeButton auditeurs

18voto

ianhanniballake Points 18370

Non, à partir du 1.0.0-alpha01 il n'y a pas de prise en charge des boîtes de dialogue dans le cadre de votre graphique de navigation. Vous devez simplement continuer à utiliser show() pour montrer un DialogFragment .

1 votes

Les demandes de fonctionnalités pour la navigation peuvent être adressées au suivi des questions publiques - Veillez à exposer votre cas d'utilisation et à expliquer pourquoi les dialogues de votre graphique de navigation vous seraient utiles.

1 votes

Y a-t-il une mise à jour depuis le printemps sur le plan des dialogues ?

4 votes

@AdamHurwitz - n'hésitez pas à mettre en vedette les problème existant pour les mises à jour.

5voto

Niyas Points 232

Oui c'est possible, vous pouvez accéder à la vue du fragment parent depuis le fragment de dialogue en appelant getParentFragment().getView() . Et utiliser la vue pour la navigation.

Voici l'exemple

Navigation.findNavController(getParentFragment().getView()).navigate(R.id.nextfragment);

5voto

Allan Veloso Points 881

Oui . Le cadre est conçu de manière à ce que vous puissiez créer une classe prolongeant le modèle Navigator classe abstraite pour les vues qui ne sont pas fournies par la boîte et l'ajouter à votre NavController avec la méthode getNavigatorProvider().addNavigator(Navigator navigator)

Si vous utilisez le NavHostFragment vous devrez également l'étendre pour ajouter le navigateur personnalisé ou simplement créer votre propre navigateur. MyFragment mise en œuvre de NavHost interface. Elle est si flexible que vous pouvez créer vos propres paramètres xml avec des attrs personnalisés définis dans le fichier values comme vous le faites en créant des vues personnalisées. Quelque chose comme ceci (non testé) :

@Navigator.Name("dialog-fragment")
class DialogFragmentNavigator(
        val context: Context,
        private val fragmentManager: FragmentManager
) : Navigator<DialogFragmentNavigator.Destination>() {

    override fun navigate(destination: Destination, args: Bundle?,
                          navOptions: NavOptions?, navigatorExtras: Extras?
    ): NavDestination {
        val fragment = Class.forName(destination.name).newInstance() as DialogFragment
        fragment.show(fragmentManager, destination.id.toString())
        return destination
    }

    override fun createDestination(): Destination = Destination(this)

    override fun popBackStack() = fragmentManager.popBackStackImmediate()

    class Destination(navigator: DialogFragmentNavigator) : NavDestination(navigator) {

        // The value of <dialog-fragment app:name="com.example.MyFragmentDialog"/>
        lateinit var name: String

        override fun onInflate(context: Context, attrs: AttributeSet) {
            super.onInflate(context, attrs)
            val a = context.resources.obtainAttributes(
                    attrs, R.styleable.FragmentNavigator
            )
            name = a.getString(R.styleable.FragmentNavigator_android_name)
                    ?: throw RuntimeException("Error while inflating XML. " +
                            "`name` attribute is required")
            a.recycle()
        }
    }
}

Utilisation

ma_navigation.xml

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/navigation"
    app:startDestination="@id/navigation_home">

    <fragment
        android:id="@+id/navigation_assistant"
        android:name="com.example.ui.HomeFragment"
        tools:layout="@layout/home">
        <action
            android:id="@+id/action_nav_to_dialog"
            app:destination="@id/navigation_dialog" />
    </fragment>

    <dialog-fragment
        android:id="@+id/navigation_dialog"
        android:name="com.example.ui.MyDialogFragment"
        tools:layout="@layout/my_dialog" />

</navigation>    

Le fragment qui va naviguer.

class HomeFragment : Fragment(), NavHost {

    private val navControllerInternal: NavController by lazy(LazyThreadSafetyMode.NONE){
        NavController(context!!)
    }

    override fun getNavController(): NavController = navControllerInternal

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Built-in navigator for `fragment` XML tag
        navControllerInternal.navigatorProvider.addNavigator(
            FragmentNavigator(context!!, childFragmentManager, this.id)
        )
        // Your custom navigator for `dialog-fragment` XML tag
        navControllerInternal.navigatorProvider.addNavigator(
            DialogFragmentNavigator(context!!, childFragmentManager)
        )
        navControllerInternal.setGraph(R.navigation.my_navigation)
    }

    override fun onCreateView(inflater: LayoutInflater, 
                              container: ViewGroup?, savedInstanceState: Bundle?): View? {
        super.onCreateView(inflater, container, savedInstanceState)
        val view = inflater.inflate(R.layout.home)
        view.id = this.id

        view.button.setOnClickListener{
            getNavController().navigate(R.id.action_nav_to_dialog)
        }

        return view
    }
}

3voto

STAR_ZERO Points 554

J'ai créé un navigateur personnalisé pour DialogFragment.

L'échantillon est aquí .
(C'est juste un échantillon, donc ça peut être n'importe quel problème).

@Navigator.Name("dialog_fragment")
class DialogNavigator(
    private val fragmentManager: FragmentManager
) : Navigator<DialogNavigator.Destination>() {

    companion object {
        private const val TAG = "dialog"
    }

    override fun navigate(destination: Destination, args: Bundle?, 
            navOptions: NavOptions?, navigatorExtras: Extras?) {
        val fragment = destination.createFragment(args)
       fragment.setTargetFragment(fragmentManager.primaryNavigationFragment, 
               SimpleDialogArgs.fromBundle(args).requestCode)
        fragment.show(fragmentManager, TAG)
        dispatchOnNavigatorNavigated(destination.id, BACK_STACK_UNCHANGED)
    }

    override fun createDestination(): Destination {
        return Destination(this)
    }

    override fun popBackStack(): Boolean {
        return true
    }

    class Destination(
            navigator: Navigator<out NavDestination>
    ) : NavDestination(navigator) {

        private var fragmentClass: Class<out DialogFragment>? = null

        override fun onInflate(context: Context, attrs: AttributeSet) {
            super.onInflate(context, attrs)
            val a = context.resources.obtainAttributes(attrs,
                    R.styleable.FragmentNavigator)
            a.getString(R.styleable.FragmentNavigator_android_name)
                    ?.let { className ->
                fragmentClass = parseClassFromName(context, className, 
                        DialogFragment::class.java)
            }
            a.recycle()
        }

        fun createFragment(args: Bundle?): DialogFragment {
            val fragment = fragmentClass?.newInstance()
                ?: throw IllegalStateException("fragment class not set")
            args?.let {
                fragment.arguments = it
            }
            return fragment
        }
    }
}

0 votes

Alors que la bibliothèque est en phase alpha, elle évolue comme une folle. Cette implémentation ne fonctionne plus dans la version alpha11.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X