#🎯 Application Native ≠ Site Web

Une application Android n’est pas un site web ! Contrairement au web où la navigation est très libre, une application native suit des patterns de navigation et des guidelines de design système stricts (Material Design) pour assurer une expérience utilisateur cohérente et familière.

Vous allez avoir besoin d’un ou plusieurs patterns de navigation pour structurer votre application.

#đź§­ Patterns de Navigation Principaux

Les informations sont récupérées depuis le site de Material Design : Layout

Sur Android il existe un pattern de navigation très populaire : le Navigation Drawer. Il s’agit d’un menu latéral qui permet d’accéder à des destinations principales dans une application.

On ne le retrouve pas sur iOS initialement, mais il est possible de l’implémenter depuis quelques version d’iOS.

  • Exemple d’utilisation

📚 Ressources

#Bottom Navigation (Tab Bar)

Une bottom navigation permet d’accéder rapidement à des destinations principales dans une application. Elle est généralement utilisée pour des applications avec 3 à 5 destinations principales.

  • Exemple d’utilisation

📚 Ressources

#2. 🔀 Sous-Structure de Navigation

Une fois que vous avez un pattern de navigation principal, vous allez surement avoir besoin de sous-structures de navigation pour organiser votre application.

#List-Detail - (Top App Bar)

  • C’est le pattern quasi universel, il peut ĂŞtre utilisĂ© comme pattern principal ou comme sous-pattern en combinaison avec bottom navigation ou navigation drawer.
  • Le pattern List-Detail est un pattern fondamental oĂą l’utilisateur sĂ©lectionne un Ă©lĂ©ment dans une liste pour voir ses dĂ©tails.

#Scaffold - Compose

  • Le Scaffold est un composant de Compose qui permet de structurer une page en utilisant les composants Material Design.
  • Il permet de dĂ©finir la structure de base d’une page : Top App Bar, Bottom Navigation, FAB, etc.
  • Scaffold est un composant qui vous permet de facilement implĂ©menter le List-Detail pattern par exemple.

📚 Ressources

#🎨 Design System et Material Design

Comme vous l’avez vu dans les ressources, si vous vous baladez sur le site de Material Design, vous trouverez des guidelines très précises pour le design d’applications Android.

Et surtout vous allez trouver des liens direct vers du code permettant d’implémenter ces designs dans vos applications !

Sur-utilisez ce site !

  • Sinon vous allez passer des heures Ă  coder des composants qui existent dĂ©jĂ  dans le design system de Google.
  • PlutĂ´t que de rĂ©inventer la roue, il est prĂ©fĂ©rable d’utiliser les composants Material Design qui sont dĂ©jĂ  optimisĂ©s pour les performances et l’accessibilitĂ©.
  • En gĂ©nĂ©ral vous n’aurez qu’à les personnaliser pour les adapter Ă  votre application.

C’est un gain de temps considérable et cela permet de garantir une expérience utilisateur cohérente et familière.

#🆙 Bonnes pratiques de programmation à retenir

  • Utiliser les composants Material Design
  • Respecter la hiĂ©rarchie visuelle
  • Suivre les spacings recommandĂ©s
  • Utiliser la typographie, la couleur et les shapes Material

#Composant Navigation - Compose

A l’instar d’un react-router ou un vue-router, Compose propose une bibliothèque “Navigation” qui permet de gérer la navigation dans votre application.

#Composant Navigation

Pour mettre en place la navigation sur Compose, vous avez 2 options :

  • Navigation “Classique” via des identifiants et des routes String
  • Navigation “Type-Safe” via des objets sĂ©rialisĂ©s entre les vues

Elle est très simple à mettre en place, mais elle est moins puissante que la navigation “Type-Safe”.

On peut trouver facilement de la documentation

🛟 Installation

Exemple d’une navigation “Classique” :

kotlin
// Définition des routes
object Routes {
    const val HOME = "home"
    const val PROFILE = "profile?userId={userId}"
    const val DETAIL = "detail/{itemId}"  // Path parameter

    fun createProfileRoute(userId: String) = "profile?userId=$userId"
    fun createDetailRoute(itemId: Int) = "detail/$itemId"
}

// Setup de la navigation
NavHost(navController, startDestination = Routes.HOME) {
    composable(Routes.HOME) {
        HomeScreen(onNavigateToProfile = {
            navController.navigate(Routes.createProfileRoute("123"))
        })
    }

    composable(
        route = Routes.PROFILE,
        arguments = listOf(
            navArgument("userId") {
                type = NavType.StringType
                nullable = true
                defaultValue = null
            }
        )
    ) { backStackEntry ->
        val userId = backStackEntry.arguments?.getString("userId")
        ProfileScreen(userId = userId)
    }

    composable(
        route = Routes.DETAIL,
        arguments = listOf(
            navArgument("itemId") { type = NavType.IntType }
        )
    ) { backStackEntry ->
        val itemId = backStackEntry.arguments?.getInt("itemId") ?: 0
        DetailScreen(itemId = itemId)
    }
}

Introduite en début d’année 2024, la navigation “Type-Safe” est une manière plus robuste de gérer la navigation dans votre application, mais aussi plus jeune et donc moins documentée.

  • L’avantage est de pouvoir passer des objets entre les vues, et de pouvoir naviguer de manière plus sĂ»re.
  • Il est assez complexe de trouver la bonne syntaxe pour la mettre en musique avec un avec un Bottom Navigation ou un Navigation Drawer.

🛟 Installation

🛟 Mise en place avec un Bottom Navigation

  • La documentation officielle n’est pas si claire et ne couvre pas le cas de figure d’une navigation avec un Bottom Navigation ou un Navigation Drawer pour le moment.
  • Un exemple est disponible dans les exemples officiels de compose ici :

Et je vous donne un exemple simple pour vous aider à démarrer :

kotlin
@Serializable
data object HomeScreen

@Serializable
data class ProfileScreen(val userId: String? = null)

@Serializable
data class DetailScreen(val itemId: Int)

// Setup de la navigation
NavHost(navController, startDestination = HomeScreen) {
    composable<HomeScreen> {
        HomeScreen(onNavigateToProfile = {
            navController.navigate(ProfileScreen("123"))
        })
    }

    composable<ProfileScreen> { backStackEntry ->
        val profileScreen = backStackEntry.toRoute<ProfileScreen>()
        ProfileScreen(userId = profileScreen.userId)
    }

    composable<DetailScreen> { backStackEntry ->
        val detailScreen = backStackEntry.toRoute<DetailScreen>()
        DetailScreen(itemId = detailScreen.itemId)
    }
}