[Android Jetpack] Utiliser la vue personnalisée dans la navigation

Insérez la description de l'image iciLa navigation est l'un des composants importants de Jetpack, utilisé pour concevoir et organiser les sauts de page d'application. Étant donné que la recommandation officielle est d'utiliser Framgent pour réaliser l'implémentation de la page, la première chose qui vient à l'esprit en matière de navigation est Fragment. Mais en fait, Navigation prend également en charge d'autres types d'implémentations de page, telles que les vues personnalisées. Cet article présentera l'utilisation de la vue personnalisée dans la navigation.

Avant l'introduction officielle, passons en revue l'utilisation de base de la navigation:

Structure de base de la navigation


L'utilisation de la navigation implique principalement les objets suivants

  • Graph
    utilise XML pour concevoir la page APP (destination) et le chemin de saut entre chaque page. Android Studio fournit un éditeur pour modifier le graphique
  • NavHost
    NavHost est un conteneur utilisé pour héberger tous les nœuds du graphique. La navigation fournit une implémentation par défaut de NavHost pour Fragment NavHostFragment. On comprend que tous les fragments du graphe sont ChildFragment. Dans le scénario de vue personnalisé présenté aujourd'hui, il est également nécessaire de mettre en œuvre NavHost pour une vue personnalisée.
  • Contrôleur
    Chaque NavHost a un contrôleur, qui gère le saut entre les nœuds dans le NavHost
  • Navigator
    Controller implémente des sauts spécifiques en appelant Navigator, et Navigator entreprend des implémentations de saut spécifiques

principe de fonctionnement


Chaque page de Navigation est une destination, qui peut être Fragment, Activité ou Vue. Liez la destination source à la destination de destination via l'action, et passez de la destination actuelle à la destination de destination via l'action.

Semblable à l'activité de lancement, lorsque l'application démarre, une destination de départ doit être définie comme affichage de la page d'accueil.

Comme mentionné précédemment, NavHost a des implémentations spécifiques pour différentes destinations. NavController propose également différentes méthodes d'acquisition en fonction du type de destination, mais elles sont toutes similaires:

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

Après avoir obtenu le contrôleur, vous pouvez navigate(int)passer, par exemple

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

la mise en oeuvre


La composition de base et le principe de fonctionnement de la navigation ont été présentés ci-dessus, puis nous entrerons dans le sujet pour réaliser la navigation basée sur une vue personnalisée.

Les éléments suivants doivent être atteints:

  • AfficherNavigator
  • Attributs pour ViewNavigator
  • AfficherDestination
  • NavigationHostView
  • Fichier graphique

AfficherNavigator

La navigation offre un moyen de personnaliser Navigator: utilisez des @Navigator.Nameannotations.
Nous définissons un nom pour screen_viewle navigateur, dans le graphique xml peut être défini par ce nom correspondant NavDestination.
NavDestination et Navigator sont limités par des génériques: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 {
    
    ...}
}

Attributs pour ViewNavigator

Définir les attributs personnalisés utilisés dans Xml pour Navigator layoutId,

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

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

</resources>

AfficherDestination

@NavDestination.ClassTypePermettez-nous de définir le nôtreNavDestination

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

Dans onInflate, recevez et analysez layoutIdla valeur de l' attribut personnalisé

NavigationHostView

Définir l'implémentation de NavHost NavigationHostFrame, qui est principalement utilisé pour créer un contrôleur, enregistrer le type de navigateur et définir un graphique pour celui-ci

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
}

Fichier graphique

Dans le fichier Graph, en <screen_view/>définissant 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>

Ouvrez l'éditeur de navigation d'Android Studio et voyez le résultat après Xml:
Insérez la description de l'image ici

Configuration en activité

Enfin, utilisez ce NavigationHostView comme conteneur dans la disposition de l'activité et associez NavController à NavHost dans le code

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

Appelez NavController dans onBackPressed` pour permettre à chaque NavDestination de prendre en charge BackPress

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

Conclusion


La navigation basée sur Fragment fournit une implémentation prête à l'emploi et réserve en même temps une interface extensible via des annotations, ce qui est pratique pour les développeurs pour personnaliser l'implémentation et même profiter de la traversée apportée par l'éditeur Android Studio.

Au début de l'instabilité de Fragment, de nombreuses alternatives à Fragment sont apparues pour la segmentation de l'interface utilisateur. Si ces frameworks sont toujours utilisés dans votre projet, vous pouvez désormais adapter la navigation pour eux avec plaisir ~

Je suppose que tu aimes

Origine blog.csdn.net/vitaviva/article/details/109281582
conseillé
Classement