Interface Utilisateur Native dans Kotlin pour Android

Ce tutoriel explique comment réaliser des actions graphiques de base avec Kotlin, dans un projet Android Studio, d’ores et déjà configuré avec Kotlin (cf. Configurer Kotlin dans un projet Android Studio [AK 2]). Le but est de créer une interface graphique simple.

GIF demo

Dans cet article, il est expliqué comment :

Note : Historiquement, avec le langage Kotlin, la bibliothèque Anko Commons [1] était utilisée pour réaliser des développements classiques liés principalement à l’interface graphique. Puis, les incontournables bibliothèques de développement d’application mobile Android avec le langage Kotlin étaient :

  • Splitties [4] : ensemble de bibliothèques Kotlin multiplateformes légères
  • KTX [5] : ensemble d’extensions Kotlin soutenues par Google

Par ailleurs, une bonne pratique est d’utiliser le View Binding afin d’accéder facilement aux éléments d’une vue XML (cf. AK-4).

Afficher un message court

Afin de présenter des messages d’information court à l’utilisateur, le SDK Android fournit la classe Toast (cf. documentation officiel).

Avec le SDK Android, cela revient à utiliser la classe Toast, dont l’import correspond à import android.widget.Toast, depuis une Activity. Elle permet de créer un message avec makeText(), cette dernière prend 3 paramètres :

  • le contexte de l’application (this depuis une Activity, requireActivity depuis un Fragment)
  • le message
  • la durée d’affichage long ou court

Enfin, il s’agit d’afficher le message ainsi créé via la fonction show() (l’appel indispensable à ne pas oublier lorsqu’on code à la plage ;).

Toast.makeText(this, "${getString(R.string.text_island)}", Toast.LENGTH_SHORT).show()

ou bien alternativement :

Toast.makeText(this, "${getString(R.string.text_island)}", Toast.LENGTH_LONG).show()

Ouvrir une boite de dialogue

Avec le SDK Android, cela revient à créer une classe DialogFragment (cf. documentation Dialogs), puis à l’utiliser depuis une Activity :

class FireMissilesDialogFragment : DialogFragment() {

    override fun onCreateDialog(savedInstanceState: Bundle): Dialog {
        return activity?.let {
            // Use the Builder class for convenient dialog construction
            val builder = AlertDialog.Builder(it)
            builder.setMessage(R.string.dialog_fire_missiles)
                    .setPositiveButton(R.string.fire,
                            DialogInterface.OnClickListener { dialog, id ->
                                // FIRE ZE MISSILES!
                            })
                    .setNegativeButton(R.string.cancel,
                            DialogInterface.OnClickListener { dialog, id ->
                                // User cancelled the dialog
                            })
            // Create the AlertDialog object and return it
            builder.create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }
}

Une alternative est de créer la boîte de dialogue, avec AlertDialog directement dans l’Activity.

Retrouvez le code dans le thème “Interface Utilisateur Native” de l’application “Kotlin pour Android”.

Alert Dialog sous Android avec kotlin

Ouvrir une page Internet

Afin d’ouvrir une page Internet avec le navigateur natif, il s’agit d’utiliser une intention fournit par le SDK Android, tout comme le lancement d’un second écran.

Plus précisément, cela revient à utiliser la classe Intent, comme suit, depuis une Activity :

val url = "https://www.chillcoding.com/"
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(url)
startActivity(i)
  1. Créez la fonction browse() :

     private fun browse(url: String) {
       var browser = Intent(Intent.ACTION_VIEW, Uri.parse("https://"+url))
       startActivity(browser)
     }
    
  2. Appelez la fonction ainsi créée sur un bouton :

     findViewById<Button>(R.id.mainBtn).setOnClickListener { browse("www.chillcoding.com") }
    

Proposer d’envoyer un email

Afin de proposer d’envoyer un email, à l’utilisateur, avec une application native, le SDK Android fournit la classe Intent avec un paramétrage spécifique.

Plus précisément, cela revient à utiliser la classe Intent, instanciée de la façon suivante :

val intent = new Intent(Intent.ACTION_SENDTO);
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("hello@chillcoding.com"))
intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.subject_feedback))
intent.putExtra(Intent.EXTRA_TEXT, "")

startActivity(Intent.createChooser(intent, "Send Email"))
  1. Créez la fonction sendEmail() :

     private fun sendEmail(to: String, subject: String, msg: String) {
       val emailIntent = Intent(Intent.ACTION_SEND)
    
       emailIntent.data = Uri.parse("mailto:")
       emailIntent.type = "text/plain"
       emailIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf(to))
       emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject)
       emailIntent.putExtra(Intent.EXTRA_TEXT, msg)
    
       try {
           startActivity(Intent.createChooser(emailIntent, getString(R.string.title_send_email)))
       } catch (ex: ActivityNotFoundException) {
           toast(R.string.text_no_email_client)
       }
     }
    
  2. Appelez la fonction ainsi créée sur un bouton :

     sendEmail("macha@chillcoding.com", "Hi", "Hello!")
    

Proposer de partager du contenu

Afin de proposer de partager du contenu via les applications disponibles, installées au préalable par l’utilisateur (Slack, Messenger, etc.), le SDK Android fournit la classe Intent avec un paramétrage spécifique.

Plus précisément, cela revient à utiliser la classe Intent de la façon suivante :

val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.app_name))
intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.text_share_app))

startActivity(Intent.createChooser(intent, "Share"))
  1. Dans un nouveau fichier Tool.kt, implémentez la fonction d’extension :
    fun Context.share(text: Int, subject: Int = R.string.app_name): Boolean {
     try {
         val intent = Intent(android.content.Intent.ACTION_SEND)
         intent.type = "text/plain"
         intent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(subject))
         intent.putExtra(android.content.Intent.EXTRA_TEXT, getString(text))
         startActivity(Intent.createChooser(intent, null))
         return true
     } catch (e: ActivityNotFoundException) {
         e.printStackTrace()
         return false
     }
    }
    
  2. Appelez la fonction share() :

     share(R.string.text_share, R.string.title_share)
    

Lancer un autre écran

Afin d’empiler un second écran dans la pile d’écrans, le SDK Android fournit la classe Intent (cf. documentation officiel), représentant une intention, à combiner avec startActivity().

Avec le SDK Android, cela revient à utiliser la classe Intent, dont l’import correspond à import android.content.Intent, depuis une Activity :

val intent = Intent(this, MySecondaryActivity::class.java)
intent.putExtra("id", 3)
intent.putExtra("name", "Macha")
startActivity(intent)

Note : Les données peuvent être récupérées via arguments.getExtra("givenkey") (soit arguments.getExtra("id") depuis la seconde Activity.

Une alternative est d’utiliser la bibliothèque navigation de Jetpack afin de gérer l’enchainement des écrans de l’application mobile Android (cf. d.android.com: Navigation for responsive UIs).

Afficher un message d’erreur

Afin d’afficher des messages dans la console du développeur Logcat, soit dans la console Android Monitor, le SDK Android fournit la classe Log (cf. documentation officiel). Il s’agit d’utiliser les méthodes Log.i(), Log.e(), etc. Elles prennent 2 paramètres :

  • un TAG, une chaine de caractères comprenant le nom de la classe courante
  • le message à afficher dans la console

Avec le SDK Android, cela revient à utiliser la classe Log dont l’import correspond à import android.util.Log :

 Log.i(MainActivity::class.simpleName, "Kotlin is an island")

Retour d’expérience

Finalement, ces implémentations peuvent être codées via des fonctions d’extensions Kotlin. En particulier, cela permet de programmer très rapidement les tâches utilisateurs les plus courantes :

La connaissance du SDK Android est alors bienvenue. Aussi, l’implémentation de ses propres fonctions d’extensions peuvent être restreintes à un contexte spécifique, c’est-à-dire qu’elles peuvent être appelées depuis une Activity (context) ou bien depuis un Fragment (requireContext).

Par ailleurs, utiliser une bibliothèque c’est cool, cela dit si elle n’est pas soutenue par Google alors cela peut tomber à l’eau… En effet, mettre à jour une bibliothèque est fastidieux.

Aussi, Google soutient des nouveautés et ces dernières ne sont pas immédiatement adoptées par la communauté. Par exemple, le langage Kotlin a pris plusieurs années avant d’avoir une autorité et prendre la place méri†ée.

Compose c’est de la bombe cela dit il n’est pas intéressant de convertir les UIs XML des anciens projets en @Composable. Cependant avec l’intéropérabilité il est possible de mixer Compose et interface graphique XML.

Pour finir, il est important de savoir ce qu’il y a sous le capot (Cmd ou Ctrl + clique :) afin de voir les implémentations originales. Parfois, il est nécessaire de mettre les mains dans le cambouis afin de développer une fonctionnalité plus évoluée, voir plus complexe, voir plus adaptée à ses besoins. L’existant est alors une source d’inspiration.

Références :

  1. GoodBye Anko on GitHub
  2. Setting up a Material Components theme for Android
  3. Choose an open source license
  4. Splitties: All the Android splits
  5. Android KTX, Part of Android Jetpack.

Partagez ou réagissez sur Twitter.

Vous avez trouvé une erreur ou voulez améliorer cet article ? Editez le directement !

Comments