[Android Jetpack] Verwenden Sie die benutzerdefinierte Ansicht in der Navigation

Fügen Sie hier eine Bildbeschreibung einDie Navigation ist eine der wichtigen Komponenten in Jetpack, mit der App-Seitensprünge entworfen und organisiert werden. Da die offizielle Empfehlung lautet, Framgent für die Seitenimplementierung zu verwenden, fällt Ihnen als Erstes Fragment ein, wenn Sie die Navigation erwähnen. Tatsächlich unterstützt die Navigation jedoch auch andere Arten von Seitenimplementierungen, z. B. benutzerdefinierte Ansichten. In diesem Artikel wird die Verwendung der benutzerdefinierten Ansicht in der Navigation vorgestellt.

Lassen Sie uns vor der formalen Einführung die grundlegende Verwendung der Navigation überprüfen:

Grundstruktur der Navigation


Die Verwendung der Navigation umfasst hauptsächlich die folgenden Objekte

  • Graph
    verwendet XML, um die Seite (das Ziel) der APP und den Sprungpfad zwischen den einzelnen Seiten zu entwerfen. Android Studio bietet einen Editor zum Bearbeiten des Graphen.
  • NavHost
    NavHost ist ein Container, in dem alle Knoten im Diagramm gehostet werden. Die Navigation bietet eine Standardimplementierung von NavHost für Fragment NavHostFragment. Es versteht sich, dass alle Fragmente im Diagramm ChildFragment sind. In dem heute vorgestellten benutzerdefinierten Ansichtsszenario ist auch die NavHost-Implementierung für die benutzerdefinierte Ansicht erforderlich.
  • Controller
    Jeder NavHost verfügt über einen Controller, der den Sprung zwischen den Knoten im NavHost verwaltet
  • Navigator
    Controller implementiert bestimmte Sprünge durch Aufrufen von Navigator, und Navigator führt bestimmte Sprungimplementierungen durch

Arbeitsprinzip


Jede Seite in der Navigation ist ein Ziel, das Fragment, Aktivität oder Ansicht sein kann. Verknüpfen Sie das Quellziel mit dem Ziel Ziel durch Aktion und springen Sie vom aktuellen Ziel zum Ziel Ziel durch Aktion.

Ähnlich wie bei der Startaktivität muss beim Starten der APP ein Startziel als Startseitenanzeige definiert werden.

Wie bereits erwähnt, verfügt NavHost über spezifische Implementierungen für verschiedene Ziele. NavController verfügt je nach Zieltyp auch über unterschiedliche Erfassungsmethoden, die jedoch alle ähnlich sind:

  • Fragment.findNavController ()
  • View.findNavController ()
  • Activity.findNavController (viewId: Int)

Nachdem Sie den Controller erhalten haben, können Sie navigate(int)beispielsweise durchspringen

findNavController().navigate(R.id.action_first_view_to_second_view)
findNavController().navigate(R.id.second_view)

Implementierung


Die grundlegende Zusammensetzung und das Funktionsprinzip der Navigation wurden im vorherigen Abschnitt vorgestellt. Anschließend werden wir das Thema eingeben, um die Navigation basierend auf der benutzerdefinierten Ansicht zu realisieren.

Folgendes muss erreicht werden:

  • ViewNavigator
  • Attribute für ViewNavigator
  • ViewDestination
  • NavigationHostView
  • Diagrammdatei

ViewNavigator

Die Navigation bietet eine Möglichkeit zum Anpassen des Navigators: Verwenden Sie @Navigator.NameAnmerkungen.
Wir definieren einen Namen für screen_viewden Navigator, in dem XML-Diagramm kann durch diesen Namen die entsprechende NavDestination definiert werden.
NavDestination und Navigator sind generisch eingeschränkt:Navigator<out NavDestination>

@Navigator.Name("screen_view")
class ViewNavigator(private val container: ViewGroup) : Navigator<ViewDestination>() {
    
    
    override fun navigate(...) {
    
    ...}
    override fun createDestination(): ViewDestination = ViewDestination(this)
    override fun popBackStack(): Boolean {
    
    ...}
}

Attribute für ViewNavigator

Definieren Sie benutzerdefinierte Attribute, die in XML für Navigator verwendet layoutIdwerden.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="ViewNavigator">
        <attr name="layoutId" format="reference" />
    </declare-styleable>

</resources>

ViewDestination

@NavDestination.ClassTypeErlauben Sie uns, unsere eigenen zu definierenNavDestination

@NavDestination.ClassType(ViewGroup::class)
class ViewDestination(navigator: Navigator<out NavDestination>) : NavDestination(navigator) {
    
    

    @LayoutRes var layoutId: Int = 0

    override fun onInflate(context: Context, attrs: AttributeSet) {
    
    
        super.onInflate(context, attrs)
        context.resources.obtainAttributes(attrs, R.styleable.ViewNavigator).apply {
    
    
            layoutId = getResourceId(R.styleable.ViewNavigator_layoutId, 0)
            recycle()
        }
    }
}

In onInflate, empfangen und analysieren , layoutIdden Wert des benutzerdefinierten Attributs

NavigationHostView

Definieren Sie die Implementierung von NavHost NavigationHostFrame, die hauptsächlich zum Erstellen von Controllern verwendet wird, registrieren Sie den Navigatortyp und legen Sie Graph dafür fest

class NavigationHostFrame(...) : FrameLayout(...), NavHost {
    
    
    private val navigationController = NavController(context)
    init {
    
    
        Navigation.setViewNavController(this, navigationController)
        navigationController.navigatorProvider.addNavigator(ViewNavigator(this))
        navigationController.setGraph(R.navigation.navigation)
    }
    override fun getNavController() = navigationController
}

Diagrammdatei

<screen_view/>Definieren Sie in der Diagrammdatei NavDestination

<?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/main_navigation"
    app:startDestination="@id/first_screen_view"
    tools:ignore="UnusedNavigation">

    <screen_view
        android:id="@+id/first_screen_view"
        app:layoutId="@layout/screen_view_first"
        tools:layout="@layout/screen_view_first">

        <action
            android:id="@+id/action_first_screen_view_to_second_screen_view"
            app:destination="@id/second_screen_view"
            app:launchSingleTop="true"
            app:popUpTo="@+id/first_screen_view"
            app:popUpToInclusive="false" />

        <action
            android:id="@+id/action_first_screen_view_to_last_screen_view"
            app:destination="@id/last_screen_view"
            app:launchSingleTop="true"
            app:popUpTo="@+id/first_screen_view"
            app:popUpToInclusive="false" />

    </screen_view>

    <screen_view
        android:id="@+id/second_screen_view"
        app:layoutId="@layout/screen_view_second"
        tools:layout="@layout/screen_view_second">

        <action
            android:id="@+id/action_second_screen_view_to_screen_view_third"
            app:destination="@id/screen_view_third"
            app:launchSingleTop="true"
            app:popUpTo="@+id/main_navigation"
            app:popUpToInclusive="true" />

    </screen_view>

    <screen_view
        android:id="@+id/last_screen_view"
        app:layoutId="@layout/screen_view_last"
        tools:layout="@layout/screen_view_last" />

    <screen_view
        android:id="@+id/screen_view_third"
        app:layoutId="@layout/screen_view_third"
        tools:layout="@layout/screen_view_third" />

</navigation>

Öffnen Sie den Navigationseditor von Android Studio und sehen Sie das Ergebnis nach XML:
Fügen Sie hier eine Bildbeschreibung ein

Setup in Aktivität

Verwenden Sie diese NavigationHostView schließlich als Container im Layout der Aktivität und ordnen Sie NavController im Code NavHost zu

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.my.sample.navigation.NavigationHostView
        android:id="@+id/main_navigation_host"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
    
    
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    navController = Navigation.findNavController(mainNavigationHost)
    Navigation.setViewNavController(mainNavigationHost, navController)
}

Rufen Sie NavController in onBackPressed` auf, damit jedes NavDestination BackPress unterstützt

override fun onSupportNavigateUp(): Boolean = navController.navigateUp()
override fun onBackPressed() {
    
    
      if (!navController.popBackStack()) {
    
    
          super.onBackPressed()
      }
}

Fazit


Die auf Fragment basierende Navigation bietet eine sofort einsatzbereite Implementierung und reserviert gleichzeitig eine erweiterbare Benutzeroberfläche durch Anmerkungen, die es Entwicklern erleichtert, die Implementierung anzupassen und sogar die vom Android Studio-Editor bereitgestellte Durchquerung zu genießen.

In den frühen Tagen der Instabilität von Fragment wurden viele Alternativen zu Fragment für die UI-Segmentierung angezeigt. Wenn diese Frameworks in Ihrem Projekt noch verwendet werden, können Sie die Navigation jetzt problemlos für sie anpassen ~

Ich denke du magst

Origin blog.csdn.net/vitaviva/article/details/109281582
Empfohlen
Rangfolge