web-dev-qa-db-fra.com

Composant d'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 les utiliser avec les nouvelles fonctionnalités de mon graphique de navigation.

17
Leonardo Deleon

Non, à partir de la version 1.0.0-alpha01, les dialogues ne sont plus pris en charge dans votre graphique de navigation. Vous devriez simplement continuer à utiliser show () pour afficher une DialogFragment.

13
ianhanniballake

Oui, c'est possible. Vous pouvez accéder à la vue du fragment parent à partir du fragment de dialogue en appelant getParentFragment (). GetView (). Et utilisez la vue pour la navigation.

Voici l'exemple

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

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

Échantillon est ici .
(C'est juste un échantillon, donc ça pourrait ê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
        }
    }
}
1
STAR_ZERO

Oui . La structure est conçue de sorte que vous puissiez créer une classe étendant la classe abstraite Navigator pour les vues qui ne sortent pas de la boîte et l'ajouter à votre NavController avec la méthode getNavigatorProvider().addNavigator(Navigator navigator).

Si vous utilisez la variable NavHostFragment, vous devrez également l'étendre pour ajouter le navigateur personnalisé ou simplement créer votre propre interface MyFragment mettant en œuvre NavHost. Il est si flexible que vous pouvez créer vos propres paramètres xml avec des attributs personnalisés définis dans values, comme pour la création de vues personnalisées. Quelque chose comme ça (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()
        }
    }
}

Usage

mon_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
    }
}
0
Allan Veloso

Une option consisterait simplement à utiliser un fragment régulier et à lui donner l’apparence d’un dialogue. J'ai trouvé que ça ne valait pas la peine, alors j'ai utilisé la méthode standard en utilisant show (). Si vous insistez Voir ici pour une façon de le faire.

0
Jeffrey