Navigationsarchitekturkomponente – Dialogfragmente

Lesezeit: 1 Minute

Benutzer-Avatar
Leonardo Deleon

Kann die neue Navigationsarchitekturkomponente mit DialogFragment verwendet werden? Muss ich einen benutzerdefinierten Navigator erstellen?

Ich würde sie gerne mit den neuen Funktionen in meinem Navigationsdiagramm verwenden.

Benutzer-Avatar
MatPag

Aktualisierung Mai 2019:

DialogFragment werden jetzt ab vollständig unterstützt Navigation 2.1.0können Sie mehr lesen hier und hier

Alte Antwort für Navigation <= 2.1.0-alpha02:

Ich bin so vorgegangen:

1) Aktualisieren Navigation Bibliothek mindestens bis zur Version 2.1.0-alpha01 und kopiere beide Dateien davon modifizierter Kern in Ihrem Projekt.

2) Ändern Sie dann in Ihrem Navigationshostfragment die name Parameter nach Ihren Wünschen 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) Erstelle dein DialogFragment Unterklassen und fügen Sie sie Ihrer hinzu nav_graph.xml mit:

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

4) Starten Sie sie jetzt aus Fragmenten oder Aktivitäten mit

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

oder ähnliche Methoden.

  • Ich habe es mit der letzten Version versucht und es funktioniert, aber Animationen laufen nicht für mich. Ich muss sie in der Dialogklasse setzen. Geht das jemandem auch so?

    – JSR – Silicornio

    21. Mai 2019 um 17:19 Uhr

  • Wie man mit seinem Positiv- und Negativ-Klick-Listener umgeht.

    – Pinakin Kansara

    22. Juli 2019 um 9:32 Uhr

  • @Pinakin Sie handhaben Ergebnisse direkt in Ihrem Benutzerkonto DialogFragmentzum Beispiel mit der onCreateDialog und Einstellung a setPositiveButton und setNegativeButton Zuhörer

    – MatPag

    9. März 2020 um 16:54 Uhr

  • kann ich das für TimePickerFragment implementieren?

    – Rizki Oktavia Ningrum

    13. April 2020 um 1:50 Uhr

  • @Pinakin Wenn Sie die Navigation verwenden, um zu einem Dialogfragment zu gelangen, stellen Sie sich das so vor, als würden Sie zu einem anderen Fragment navigieren. Wie würden Sie ein Ergebnis zurückbekommen, wenn Sie zu einem regulären Fragment navigieren? developer.android.com/training/basics/fragments/… Wenn der Dialog dem Fragment gehört, das ihn gestartet hat, und Sie Click-Listener wünschen, ist die Verwendung von a möglicherweise besser Dialog und Navigation überspringen.

    – Viktor Rendina

    29. Juli 2020 um 12:50 Uhr


Nein, ab dem 1.0.0-alpha01 build, gibt es keine Unterstützung für Dialoge als Teil Ihres Navigationsdiagramms. Sie sollten einfach weiter verwenden Show() ein zeigen DialogFragment.

  • Funktionsanfragen für die Navigation können an die gerichtet werden öffentlicher Issue-Tracker – Stellen Sie sicher, dass Sie Ihren Anwendungsfall angeben und warum Sie Dialoge in Ihrem Navigationsdiagramm nützlich finden würden.

    – ianhanniballake

    13. Mai 2018 um 0:34 Uhr

  • Gibt es seit dem Frühjahr eine Aktualisierung des Plans für Dialoge?

    – Adam Hurwitz

    23. August 2018 um 19:34 Uhr

  • @AdamHurwitz – Fühlen Sie sich frei, die zu staren bestehendes Problem für Aktualisierungen.

    – ianhanniballake

    23. August 2018 um 20:16 Uhr

  • Akzeptierte Antwort ist nicht mehr gültig als DialogFragment wird jetzt mit unterstützt 2.1.0-alpha03 Ausführung

    – Musooff

    3. August 2019 um 15:45 Uhr

  • Sie müssen nur Ihr DialogFragment in NavGraph als Antwort von Razor unten ändern!

    – Andy

    23. Oktober 2020 um 15:29 Uhr

Benutzer-Avatar
Allan Veloso

Ja. Das Framework ist so gemacht, dass Sie eine Klasse erstellen können, die das erweitert Navigator abstrakte Klasse für die Ansichten, die nicht standardmäßig vorhanden sind, und fügen Sie sie Ihrer hinzu NavController mit der Methode getNavigatorProvider().addNavigator(Navigator navigator)

Wenn Sie die verwenden NavHostFragmentmüssen Sie es auch erweitern, um den benutzerdefinierten Navigator hinzuzufügen, oder einfach Ihren eigenen erstellen MyFragment umsetzen NavHost Schnittstelle. Es ist so flexibel, dass Sie Ihre eigenen XML-Parameter mit benutzerdefinierten Attributen erstellen können, die in definiert sind values, so wie Sie benutzerdefinierte Ansichten erstellen. Etwa so (nicht getestet):

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

Verwendungszweck

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

Das Fragment, das navigiert.

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

Benutzer-Avatar
Niyas

Ja, das ist möglich. Sie können über das Dialogfragment auf die Ansicht des übergeordneten Fragments zugreifen, indem Sie anrufen getParentFragment().getView(). Und nutzen Sie die Ansicht zur Navigation.

Hier ist das Beispiel

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

Benutzer-Avatar
STAR_ZERO

Ich habe einen benutzerdefinierten Navigator für DialogFragment erstellt.

Probe ist hier.
(Es ist nur ein Beispiel, daher könnte es ein Problem geben.)

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

  • Während die Bibliothek in Alpha ist, ändert sie sich wie verrückt. Diese Implementierung funktioniert in alpha11 nicht mehr.

    – Allan Veloso

    4. Februar 2019 um 22:04 Uhr

Version 2.1.0-alpha03 wurde veröffentlicht, damit wir endlich DialogFragments verwenden können. Leider habe ich einige Probleme mit dem Backstack, wenn ich abbrechende Dialoge verwende. Wahrscheinlich habe ich eine fehlerhafte Implementierung meiner Dialoge.

[LATER-EDIT] Meine Implementierung war gut, das Problem hängt mit der falschen Dialogzählung für DialogFragmentNavigator zusammen, wie in beschrieben Issue-Tracker
Als Workaround kannst du mal nachschauen auf meine Empfehlung

  • Während die Bibliothek in Alpha ist, ändert sie sich wie verrückt. Diese Implementierung funktioniert in alpha11 nicht mehr.

    – Allan Veloso

    4. Februar 2019 um 22:04 Uhr

Benutzer-Avatar
Rasierer

Aktualisiert für:

implementation "androidx.navigation:navigation-ui-ktx:2.2.0-rc04"

Und in my_nav_graph.xml verwenden

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

  • Dies ist die aktualisierte und korrekte Lösung! Funktioniert bei mir!

    – Andy

    23. Oktober 2020 um 15:27 Uhr

1245790cookie-checkNavigationsarchitekturkomponente – Dialogfragmente

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy