100% ont trouvé ce document utile (1 vote)
959 vues348 pages

Cours-Programmation Mobile Avec Jetpack Compose

Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
100% ont trouvé ce document utile (1 vote)
959 vues348 pages

Cours-Programmation Mobile Avec Jetpack Compose

Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

COURS DE

DÉVELOPPEMENT
D’APPLICATIONS
MOBILES
GLO 418 / IC4
Année académique : 2023-2024

UMa
Touza Isaac
ENSPM
isaac_touza@[Link]
INFOTEL
Informations générales
• Code UE : GLO418
• Intitulé de L’UE : Développement d’Applications
Mobile
• Crédit : 3
• Durée : 45h
❑ CM : 10 h
❑ TP: 15h
❑ TPE: 5h
❑ TD : 15h
• Evaluations :
❑ CC (théorique ou pratique): 2h
❑ Examen (théorique ou pratique) : 2h
❑ Rattrapage (théorique ou pratique): 2h 2
• Références :
❑ Antonio Leiva, Kotlin for Android Developers. Learn Kotlin the easy
way while developing an Android App. 22017-06-20
❑ Pierre Nerzic , Programmation mobile avec Android. IUT de
Lannion. février-mars 2021.
❑ Tutorials Point (I) Pvt. Ltd, Kotlin. 2019
❑ Peter Späth, Pro Android with Kotlin. Developing Modern Mobile
Apps. Leipzig, Germany ISBN-13 (pbk): 978-1-4842-3819-6.

3
Objectifs du cours

Objectif général:
Apprendre à développer des applications mobiles avec Kotlin.

Objectifs spécifiques :
• Maîtriser les bases de Kotlin
• Comprendre la Programmation Orientée Objet avec Kotlin
• Mettre en œuvre la programmation fonctionnelle
• S'initier aux applications Android sous Kotlin
• Utiliser efficacement jetpack compose
• Intégrer le langage Kotlin dans un projet Java existant

4
Près-requis et consignes

Près requis :
• Maitriser un langage de programmation orienté
objet (Java, C#, C++)
• Programmer en HTML

Consignes :
• Assister à tous les cours
• Etre attentifs et actifs pendant le cours
• Faire tous les exercices de TD et TP
• Refaire plusieurs fois les exercices d’applications
• Ne manquez jamais un TP
5
Recommandations

Outils logiciels:
• JDK et JRE
• Android studio
• IntelliJ IDEA

Plateformes
• YouTube
• Stackoverflow
• GitHub
6
Plan du cours
Séance 1 : Environnement de développement
Séance 2 : Introduction au langage Kotlin
Séance 3 – 6 : Programmation impérative avec kotlin
❑ Conception d’interface d’utilisateur
❑ Vie d’une application
❑ Liste
❑ Ergonomie
Séance 7 – 12 : Jetpack compose
❑ Introduction
❑ Les bases du compose
❑ Gestion des données avec compose
❑ Widgets, Interfaces personnalisées et composables avancées
❑ La navigation
❑ Test et gestion de configuration
Séance 13 : SQLite
Séance 14 : Firebase 7
SÉANCE 1

ENVIRONNEMENT
DE
DÉVELOPPEMENT
Cette matière présente la programmation d’applications natives sur Android avec
Kotlin. Il y aura 14 semaines de cours, chacune comptant 2h CM et 3h TP.
Cette semaine nous allons découvrir l’environnement de développement Android :
▪ Le SDK Android et Android Studio
▪ Création d’une application simple
▪ Communication avec un smartphone ou une tablette

9
Android: Historique et définition
❑ Né en 2004, racheté par Google en 2005, publié en 2007, version 1.5
❑ De nombreuses versions depuis. On en est à la version 14 (2023) et l’API
34.
❑ La version 13 est le numéro pour le grand public, et les versions d’API
sont pour les développeurs. Exemples:
▪ 4.1 JellyBean = API 16,
▪ 6.x Marshmallow = API 23,
▪ 9.x Pie = API 28

Android est donc un système complet pour smartphones et


tablettes
❑ Gestion matérielle : système d’exploitation Linux sous-jacent

❑ API de programmation : interfaces utilisateur, outils. . .


❑ Applications : navigateur, courrier. . .
10
Composants d'Android

Android est une surcouche au dessus d’un


système Linux.

11
Distribution des versions d’API

Une API (Application Programming Interface) est


un ensemble de bibliothèques de classes pour
programmer des applications.

12
Distribution des versions d’API

13
[Link]
Distribution des versions d’API
Remarques :
❑ Chaque API apporte des fonctionnalités supplémentaires. Il y a
compatibilité ascendante. Certaines fonctionnalités deviennent
dépréciées au fil du temps, mais restent généralement
disponibles.
❑ On souhaite toujours programmer avec la dernière API
(fonctions plus complètes et modernes), mais les utilisateurs
ont souvent des smartphones plus anciens, qui n’ont pas cette
API.
❑ Or Android ne propose aucune mise à jour majeure. Les
smartphones restent toute leur vie avec l’API qu’ils ont à la
naissance.
❑ Les développeurs doivent donc choisir une API qui correspond
à la majorité des smartphones existant sur le marché.
14
Applications Android.
Actuellement, les applications sont :
• « natives », c’est à dire programmées en Java, C++, Kotlin,
compilées et fournies avec leurs données sous la forme d’une
archive Jar (fichier APK). C’est ce qu’on étudiera ici.
• « web app », c’est une application pour navigateur internet,
développée en HTML5, CSS3, JavaScript, dans un cadre logiciel
(framework) tel que [Link], Angular ou React.
• « hybrides », elles sont développées dans un framework
comme Ionic, Flutter, React Native. . . Ces frameworks font
abstraction des particularités du système : la même application
peut tourner à l’identique sur différentes plateformes (Android,
iOS, Windows, Linux. . . ).
NB : La charge d’apprentissage est la même.
15
Applications Android.
Actuellement, les applications sont :
• « natives », c’est à dire programmées en Java, C++, Kotlin,
compilées et fournies avec leurs données sous la forme d’une
archive Jar (fichier APK). C’est ce qu’on étudiera ici.
• « web app », c’est une application pour navigateur internet,
développée en HTML5, CSS3, JavaScript, dans un cadre logiciel
(framework) tel que [Link], Angular ou React.
• « hybrides », elles sont développées dans un framework
comme Ionic, Flutter, React Native. . . Ces frameworks font
abstraction des particularités du système : la même application
peut tourner à l’identique sur différentes plateformes (Android,
iOS, Windows, Linux. . . ).
NB : La charge d’apprentissage est la même.
16
Applications Android.
Une application native Android est composée de :
▪ Code sources (Java ou Kotlin) compilés pour une machine
virtuelle appelée « ART», amélioration de l’ancienne machine «
Dalvik » (versions ≤ 4.4).
▪ Fichiers appelés ressources :
- format XML : interface, textes. . .
- format PNG : icônes, images. . .
▪ Manifeste = description du contenu du logiciel
- version minimale du smartphone,
- fichiers présents dans l’archive avec leur signature,
- demandes d’autorisations, durée de validité, etc.
Tout cet ensemble est géré à l’aide d’un IDE (environnement de
développement) appelé Android Studio qui s’appuie sur un ensemble
logiciel (bibliothèques, outils) appelé SDK Android.
17
Android Studio
Le logiciel Android Studio est un logiciel de programmation
(IDE) des applications mobiles.
Elle offre :
❑un éditeur de sources et de ressources
❑des outils de compilation : gradle
❑ des outils de test et de mise au point
Pour commencer à créer des applications mobiles, il faut
installer Android Studio selon la procédure expliquée via
cette adresse :
[Link]

18
SDK
Le Software Development Kit (SDK) contient :
❖Les librairies Java pour créer des logiciels
❖Les outils de mise en boîte des logiciels
❖AVD : un émulateur de tablettes pour tester les applications
❖ADB : un outil de communication avec les vraies tablettes
L’installation de SDK, se fait soit automatiquement avec Android
Studio, soit faire une installation personnalisée. En général, vous
pouvez choisir ce que vous voulez ajouter au SDK (version des
librairies, versions des émulateurs de smartphones), à l’aide du
SDK Manager. C’est le gestionnaire du SDK, une
application qui permet de choisir les composants à
installer et mettre à jour.
19
SDK

20
SDK
Le gestionnaire permet de
✓ choisir les versions à installer, ex. : Android 11 (API 30),
Android 7.0 (API 24) , …
✓ Choisir celles qui correspondent aux tablettes qu’on vise, mais
tout n’est pas à installer : il faut cocher Show Package
Details, puis choisir élément par élément. Seuls ceux-là sont
indispensables :
❑ Android SDK Platform
❑ Intel x86 Atom_64 System Image
Le reste est facultatif (Google APIs, sources, exemples et docs)

21
SDK
Le dossier SDK contient de sous-dossiers suivants:
• SDK Tools : indispensable, contient le gestionnaire,
• SDK Platform-tools : indispensable, contient adb,
• SDK Platform : indispensable, contient les librairies,
• System images : pour créer des AVD,
• Android Support : divers outils pour créer des applications,
• Exemples et sources.

22
Première application Android

Android Studio contient un assistant de


création d’applications :

23
Première application Android

24
Première application Android

25
Première application Android

26
SDK
L’assistant a créé de nombreux éléments visibles dans la colonne
de gauche de l’IDE :
• manifests : description et liste des classes de l’application
• java : les sources, rangés par paquetage,
• res : ressources = fichiers XML et images de l’interface, il y a
des sous-dossiers :
✓ layout : interfaces (disposition des vues sur les
✓ écrans)menu : menus contextuels ou d’application
✓ mipmap et drawable : images, icônes de l’interface
✓ values : valeurs de configuration, textes. . .
• Gradle scripts : c’est l’outil de compilation du projet.
NB: ne pas chercher à tout comprendre cette semaine 27
Structure d’un projet Android

28
Editeurs d'Android studio

29
Editeurs d'Android studio

30
Gradle
❑ Gradle est un outil de construction de projets comme Make
(projets C++ sur Unix), Ant (projets Java dans Eclipse) et
Maven.
❑ De même que make se sert d’un fichier Makefile, Gradle se
sert de fichiers nommés [Link] pour construire le
projet.
On distingue deux [Link] :
• un script [Link] dans le dossier racine du projet. Il
indique quelles sont les dépendances générales (noms des
dépôts Maven contenant les librairies utilisées).
• un dossier app contenant l’application du projet.
• un script [Link] dans le dossier app pour compiler
l’application 31
Gradle
Remarque:
Chaque modification d’une source ou d’une ressource fait
reconstruire le projet (compilation des sources, transformation
des XML et autres). C’est automatique.

32
Utilisation des bibliothèques
Certains projets font appel à des bibliothèques externes. On les
spécifie dans le [Link] du dossier app, dans la zone
dependencies :

33
Utilisation des bibliothèques
Certains projets font appel à des bibliothèques externes. On les
spécifie dans le [Link] du dossier app, dans la zone
dependencies :

Les bibliothèques indiquées sont automatiquement téléchargées.


34
Exécution de l’application
L’application est prévue pour tourner sur un appareil
(smartphone ou tablette) réel ou simulé (virtuel). Le SDK Android
permet de :
• Installer l’application sur une vraie tablette connectée par USB
• Simuler l’application sur une tablette virtuelle AVD
AVD = Android Virtual Device
C’est une machine virtuelle comme celles de VirtualBox et
VMware, mais basée sur QEMU. QEMU est en licence GPL, il
permet d’émuler toutes sortes de CPU dont des ARM7, ceux qui
font tourner la plupart des tablettes Android

35
Exécution de l’application
L’assistant de création de tablette demande :
• Modèle de tablette ou téléphone à simuler,
• Version du système Android,
• Orientation et densité de l’écran
• Options de simulation :
✓ Snapshot : mémorise l’état de la machine d’un
lancement à l’autre, mais exclut Use Host
GPU,
✓ Use Host GPU : accélère les dessins 2D et 3D
à l’aide de la carte graphique du PC.
• Options avancées :
✓ RAM : mémoire à allouer, mais est limitée par
votre PC,
✓ Internal storage : capacité de la flash interne,
✓ SD Card : capacité de la carte SD simulée
supplémentaire (optionnelle). 36
Exécution de l’application

37
Création d’un paquet installable
Un paquet Android est un fichier .apk. C’est une archive signée
(authentifiée) contenant les binaires, ressources compressées et
autres fichiers de données.
La création est relativement simple avec Studio :
1. Menu contextuel du projet Build..., choisir Generate Signed
APK,
2. Signer le paquet à l’aide d’une clé privée,
3. Définir l’emplacement du fichier .apk.

38
Création d’un paquet installable

39
Création d’un paquet installable

40
Et Voilà !
C’est fini pour cette semaine, rendez-vous la séance prochaine pour
le cours sur Kotlin.

41
SÉANCE 2

KOTLIN

42
Cette semaine nous allons découvrir le langage Kotlin :
▪ Maîtriser les bases de Kotlin
▪ Comprendre la Programmation Orientée Objet avec Kotlin
▪ Mettre en œuvre la programmation fonctionnelle

43
Présentation du langage Kotlin
• Kotlin est un langage de programmation orienté objet et
fonctionnel, avec un typage statique qui permet de compiler
pour la machine virtuelle Java, JavaScript, et vers plusieurs
plateformes en natif grâce à LLVM (Low Level Virtual Machine
en français : « machine virtuelle de bas niveau).
• Conçu Par : JetBrains
• Date de première version : 22 juillet 2011
• Dernière version : 1.9.20 (29 septembre 2022)
• Licence : Licence Apache version 2.0
• Paradigme : Objet, fonctionnel
• Site web : [Link]

44
Avantages de Kotlin

45
Pourquoi une application mobile
avec Kotlin ?

46
Pourquoi une application mobile
avec Kotlin ?

47
Exécuter un script kotlin

❑ Téléchargez la dernière version ([Link])


depuis GitHub Releases
([Link] .
❑ Décompressez le compilateur autonome dans un répertoire et
ajoutez éventuellement le répertoire bin au chemin système.
Le répertoire bin contient les scripts nécessaires pour compiler
et exécuter Kotlin sous Windows, macOS et Linux.
❑ Ecrire votre script kotlin et l’enregister sous l’extension .kt
❑ Compilez l'application à l'aide du compilateur Kotlin :

48
Exécuter un script kotlin

❑ L'option -d indique le chemin de sortie des fichiers de classe


générés, qui peuvent être soit un répertoire, soit un fichier
.jar. L'option -include-runtime rend le fichier .jar résultant
autonome et exécutable en y incluant la bibliothèque
d'exécution Kotlin.
❑ Exécutez l'application.

49
Kotlin: Déclaration de variable
Kotlin utilise deux mots clés différents pour déclarer des variables
: val et var.
❑ Utilisez val pour une variable dont la valeur ne change jamais
(constante). Vous ne pouvez pas réattribuer une valeur à une
variable déclarée à l'aide de val.
❑ Utilisez var pour une variable dont la valeur peut changer.

50
Kotlin: Inférence de type
Dans l'exemple suivant, languageName est déduit en tant que
String. Vous ne pouvez donc pas appeler des fonctions qui ne
font pas partie de la classe String :

51
Kotlin: Sécurité nulle
Dans certaines langues, une variable de type de référence peut être
déclarée sans valeur explicite initiale. Dans ces cas, les variables
contiennent généralement une valeur nulle. Par défaut, les variables
Kotlin ne peuvent pas contenir de valeurs nulles. Cela signifie que
l'extrait suivant n'est pas valide :

Pour qu'une variable puisse contenir une valeur nulle, elle doit être de
type nullable. Vous pouvez spécifier qu'une variable nullable en
ajoutant le suffixe ? à son type, comme illustré dans l'exemple suivant
:

52
Expressions conditionnelles
Kotlin propose plusieurs méthodes permettant
d'implémenter une logique conditionnelle. La plus
courante est l'instruction if-else.

53
Expressions conditionnelles
Pour éviter cette répétition, Kotlin permet d'utiliser
des expressions conditionnelles.
L'exemple peut être réécrit comme suit :

54
Expressions conditionnelles
Lorsque la complexité de votre instruction conditionnelle
augmente, vous pouvez envisager de remplacer votre
expression if-else par une expression when, comme illustré
dans l'exemple suivant :

55
Expressions conditionnelles

Exercice :
Ecrire un programme Kotlin qui affiche la mention de
l’étudiant en fonction de sa moyenne.
• 10 <= Moyenne < 12 : Passable
• Moyenne > 14 : Très Bien
• Moyenne = 20 : Parfait
NB: utiliser l’expression when.

56
Les boucles en kotlin

Répéter une action x fois


repeat(x) { i ->
action_à_repeter
}

Itérations sur les listes


val list = listOf ("element1", "element2", "element3")
for(str in list) {
action_à_realiser
}

57
Les boucles en kotlin

Itérations sur les entiers


for(i in 0..9) {
action_à_realiser
}

usage d'un index pour itérer:


for((index, element) in [Link]()) {
print("$element at index $index")
}

58
Les boucles en kotlin

Approche fonctionnelle de l’itération


[Link] {
print([Link]())
}
Les boucles while et do-while
while(condition) {
doSomething()
}
do {
doSomething()
} while (condition) 59
Les tableaux en kotlin

❑ Un tableau c’est un conteneur de variable. Les


variables qu’il contient sont du même type et
sont stockées dans des cases.
❑ Les cases représentent des adresses en mémoire
❑ En Kotlin, on définit donc le tableau de la manière
suivante :
Var NomTableau : type

Exemple: Var Tab : IntArray

60
Les tableaux en kotlin

❑ Un tableau peut également contenir un objet :


Class MonObjet
var MonTableau : Array <MonObjet>
En Kotlin, les types Int, Float, Long, Double, Char, Byte,
Short, Boolean sont également représenté en tant
qu’objet. Par conséquent on peut également écrire nos
tableaux comme ci-dessous :
var TableauBoolean : Array<Boolean>
var TableauEntier : Array<Int>
61
Les tableaux en kotlin

❑ Un tableau s’est aussi une variable, il peut


également contenir un tableau.

var Tableau_de_tableau_entier : Array<Array<Int>>

62
Les tableaux en kotlin

❑ L’initialisation est très simple, on utilise la


méthode qui se nomme le type de notre tableau
suivi de “ArrayOf” pour les variables qui ne sont
pas des objets. Pour un tableau d’objet on utilise
seulement la méthode “arrayOf”.
var TableauEntier: IntArray=intArrayof(2,10,11,33)

63
Les tableaux en kotlin
On peut parcourir un tableau de deux façons:
❑ Utilisation de la boucle “for”.
var TableauEntier: IntArray=intArrayof(2,10,11,33)
for (I in TableauEntier) {
TableauEntier[i].toString()
}
❑ la methode forEach()
var TableauEntier: IntArray=intArrayof(2,10,11,33)
[Link]{ it: Int
[Link]()
}
64
Les fonctions en kotlin
• Pour déclarer une fonction, utilisez le mot clé fun suivi
du nom de la fonction.
• Ensuite, définissez les types d'entrées que votre fonction
reçoit, le cas échéant, et déclarez le type de sortie
qu'elle renvoie.
• Le corps d'une fonction est l'endroit où vous définissez
les expressions appelées lorsque votre fonction est
appelée.
fun NomFonction (arguments et types ): type_retour {
Votre code ici
return valeur
}
65
Les fonctions en kotlin
• Pour déclarer une fonction, utilisez le mot clé fun suivi
du nom de la fonction.
• Ensuite, définissez les types d'entrées que votre fonction
reçoit, le cas échéant, et déclarez le type de sortie
qu'elle renvoie.
• Le corps d'une fonction est l'endroit où vous définissez
les expressions appelées lorsque votre fonction est
appelée.
fun NomFonction (arguments et types ): type_retour {
Votre code ici
return valeur
}
66
Les fonctions en kotlin

Exercice :
1. Ecrire une fonction Kotlin qui calcule la moyenne des
éléments d’un tableau de taille N=50

2. Ecrire une fonction Kotlin qui prend entrée deux


chaines de caractères et compare leur longueur.

67
PROGRAMMATION ORIENTEE
OBJET EN KOTLIN

68
Les classes en Kotlin
Terminologie

• Les classes sont des modèles d'objets.


• Les objets sont des instances de classes
• Les propriétés sont les caractéristiques des classes.
• Les méthodes, également appelées fonctions membres, sont
les fonctionnalités de la classe.
• Une interface est une spécification qu'une classe peut
implémenter.
• Les packages sont un moyen de regrouper du code connexe
pour le garder organisé ou de créer une bibliothèque de code.
• Encapsulation. Encapsule les propriétés et méthodes
associées qui effectuent des actions sur ces propriétés dans
une classe.

69
Les classes en Kotlin
Terminologie

• Abstraction. Il s'agit d'une extension de


l'encapsulation. L'idée est de masquer autant que
possible la logique d'implémentation interne.
• Héritage. Permet de construire une classe sur la base
des caractéristiques et du comportement d'autres
classes en établissant une relation parent-enfant.
• Polymorphisme. Le mot est une adaptation de la
racine grecque poly-, qui signifie "plusieurs", et de -
morphisme, qui signifie forme. Le polymorphisme est la
capacité à utiliser différents objets d'une façon
commune

70
Les classes en Kotlin
Définition d’une classe en Kotlin

Tous les types mentionnés jusqu'à présent sont intégrés au langage de


programmation Kotlin. Si vous souhaitez ajouter un type personnalisé,
vous pouvez définir une classe.

La définition de classe commence par le mot clé class, suivi d'un nom
et d'une série d'accolades.

71
Les classes en Kotlin
Définition d’une classe en Kotlin

Une classe comprend trois parties principales :


❑ Propriétés. Variables spécifiant les attributs des objets
de la classe.
❑ Méthodes. Fonctions contenant les comportements et
les actions de la classe.
❑ Constructeurs. Fonction membre spéciale qui crée des
instances de la classe dans tout le programme dans
lequel elle est définie.

72
Les classes en Kotlin
Propriétés d'une classe

Les propriétés sont essentiellement des variables définies


dans le corps de la classe et non dans celui de la fonction.
Cela signifie que la syntaxe utilisée pour définir les
propriétés et les variables est identique. Vous définissez
une propriété non modifiable avec le mot clé val et une
propriété modifiable avec le mot clé var.
class SmartDevice {
val name = "Android TV"
val category = "Entertainment"
var deviceStatus = "online"
}
73
Les classes en Kotlin
Instance d'une classe

Pour utiliser un objet, vous devez le créer et l'affecter à


une variable, de la même manière que vous définissez une
variable. Le mot clé val ou var est suivi du nom de la
variable, d'un opérateur d'affectation =, puis de
l'instanciation de l'objet de classe. La syntaxe est illustrée
dans le schéma ci-dessous :

74
Les classes en Kotlin
Les méthodes de classe

Les actions que la classe peut effectuer y sont définies en


tant que fonctions (méthodes).
Exemple : Définissons les méthodes turnOn() et turnOff()
dans la classe SmartDevice

75
Les classes en Kotlin
Appel d’une méthode sur un objet

❖ Pour appeler une méthode dans une classe, la procédure


est la même que celle utilisée pour appeler d'autres
fonctions à partir de la fonction main()
❖ Pour appeler une méthode de classe en dehors de la
classe, commencez par l'objet de classe suivi de
l’opérateur . , du nom de la fonction et d'une paire de
parenthèses. Le cas échéant, les parenthèses
contiennent les arguments requis par la méthode.
La syntaxe est illustrée dans le schéma ci-dessous :

76
Les classes en Kotlin
Appel d’une méthode sur un objet

Remarque :
Le principe d’une classe est d’encapsuler un ensemble de données qui
ont un certain lien entre elles, nous allons avoir besoin d’assesseurs
(getters) pour y avoir accès, et de mutateurs (setters) pour les modifier.
En Kotlin, vous n’aurez pas besoin de les déclarer explicitement. Ils
seront "générés" automatiquement grâce aux mots-clés val et var
indiqués avant chaque nom de propriété dans le constructeur de la
classe :
• val : La propriété sera immuable, vous ne pourrez donc pas la
modifier. Kotlin générera alors pour vous uniquement un assesseur.
• var : La propriété sera muable, vous pourrez la modifier. Kotlin
générera alors pour vous un assesseur et un mutateur.
Plus besoin d’utiliser les préfixes get et set devant le nom d'une
propriété : appelez directement la propriété par son nom !
77
Les classes en Kotlin
Constructeurs d'une classe

Vous pouvez définir un constructeur avec ou sans paramètres.


- Constructeur par défaut : est un constructeur sans paramètres.
Vous pouvez définir un constructeur de ce type comme indiqué dans
cet extrait de code :

La concision est l'une des caractéristiques du langage Kotlin. Vous


pouvez donc supprimer le mot clé constructor si le constructeur ne
contient ni annotations ni modificateurs de visibilité

78
Les classes en Kotlin
Constructeurs d'une classe

- Constructeur paramétré. Le constructeur accepte à présent des


paramètres pour configurer ses propriétés. Par conséquent, la façon
d'instancier un objet pour une classe de ce type change également. Le
schéma ci-dessous illustre la syntaxe complète pour instancier un objet :

79
Les classes en Kotlin
Constructeurs d'une classe

En langage Kotlin, il existe deux principaux types de constructeurs :


➢ Constructeur principal. Une classe ne peut avoir qu'un seul
constructeur principal, qui est défini dans l'en-tête de la classe. Un
constructeur principal peut être un constructeur par défaut ou
paramétré. Le constructeur principal ne possède pas de corps, ce qui
signifie qu'il ne peut pas contenir de code. Le schéma ci-dessous
illustre la syntaxe complète permettant de définir un constructeur
principal :

80
Les classes en Kotlin
Constructeurs d'une classe

➢ Constructeur secondaire. Une classe peut comporter plusieurs


constructeurs secondaires. Vous pouvez définir le constructeur
secondaire avec ou sans paramètres. Le constructeur secondaire peut
initialiser la classe et a un corps qui peut contenir la logique
d'initialisation. Si la classe comporte un constructeur principal, chaque
constructeur secondaire doit l'initialiser. Le constructeur secondaire est
inclus dans le corps de la classe et sa syntaxe se compose de trois
parties :
1. Déclaration du constructeur secondaire
2. Initialisation du constructeur principal
3. Corps du constructeur secondaire.

81
Les classes en Kotlin
Constructeurs d'une classe

82
Les classes en Kotlin
Constructeurs d'une classe

class SmartDevice(val name: String, val category: String) {


var deviceStatus = "online"

constructor(name: String, category: String, statusCode: Int) :


this(name, category) {
deviceStatus = when (statusCode) {
0 -> "offline"
1 -> "online"
else -> "unknown"
}
}
...
}
83
Les classes en Kotlin
Relation entre les classes

o En langage Kotlin, toutes les classes sont dites "finales", ce qui


signifie que vous ne pouvez pas les étendre. Vous devez donc
définir des relations entre elles.
o Le concept d'héritage vous permet de créer une classe en
vous appuyant sur les caractéristiques et le comportement
d'une autre classe. Il s'agit d'un mécanisme efficace qui vous
aide à écrire du code réutilisable et à établir des relations
entre les classes.
o Pour définir la relation entre la super-classe et ses sous-
classes, on commence par ajouter un mot clé open avant le
mot clé class pour informer le compilateur que cette classe est
extensible, de sorte que d'autres classes puissent maintenant
l'étendre. 84
Les classes en Kotlin
Relation entre les classes

Exemple d’une classe extensible

La syntaxe utilisée pour créer une sous-classe est illustrée dans le


schéma ci-dessous :

85
Les classes en Kotlin
Relation entre les classes

Exemple d’une sous-classe

Une sous classe peut posséder ses propres méthodes pouvant portés les
mêmes noms que celles de la superclasse. Pour ce faire :
• Dans le corps de la super-classe, ajoutez un mot clé open avant le
mot clé fun de chaque méthode :

86
Les classes en Kotlin
Relation entre les classes

• Dans la sous-classe, avant le mot clé fun des méthodes, ajoutez le


mot clé override, pour indiquer à l'environnement d'exécution Kotlin
d'exécuter le code inclus dans la méthode définie dans la sous-classe.

87
Les classes en Kotlin
Relation entre les classes

Appeler une méthode à partir de la super-classe revient à l'appeler


depuis l'extérieur de la classe. Au lieu d'utiliser un opérateur . entre
l'objet et la méthode, vous devez utiliser le mot clé super, qui indique au
compilateur Kotlin d'appeler la méthode sur la super-classe plutôt que
sur la sous-classe.
La syntaxe utilisée pour appeler la méthode à partir de la super-classe
commence par un mot clé super, suivi de l'opérateur . , du nom de la
fonction et d'une paire de parenthèses. Le cas échéant, les arguments
sont placés entre parenthèses. La syntaxe est illustrée dans le schéma ci-
dessous :

88
Les classes en Kotlin
Modificateurs de visibilité

Les modificateurs de visibilité jouent un rôle important pour l'obtention


de l'encapsulation :
✓ Dans une classe, ils vous permettent de masquer vos propriétés et
méthodes afin d'empêcher tout accès non autorisé depuis l'extérieur.
✓ Dans un package, ils vous permettent de masquer les classes et
interfaces afin d'empêcher tout accès non autorisé depuis l'extérieur.
Kotlin propose quatre modificateurs de visibilité :
Modificateur Accessible dans Accessible dans Accessible dans Accessible en
la même classe la sous-classe le même module dehors du
module
private ✔ 𝗫 𝗫 𝗫
protected ✔ ✔ 𝗫 𝗫
internal ✔ ✔ ✔ 𝗫
public ✔ ✔ ✔ ✔
89
Les classes en Kotlin
Modificateurs de visibilité
Remarques :
• Un module est un ensemble de fichiers sources et de
paramètres de compilation permettant de diviser le
projet en unités fonctionnelles distinctes. Votre projet
peut comporter un ou plusieurs modules. Vous pouvez
créer, tester et déboguer chaque module séparément.
• Un package est essentiellement un répertoire ou un
dossier qui regroupe des classes associées, tandis
qu'un module fournit un conteneur pour le code source,
les fichiers de ressources et les paramètres de votre
application. Un module peut contenir plusieurs
packages.
90
Les classes en Kotlin
Modificateurs de visibilité

Lorsque vous définissez une classe, elle est visible


publiquement et tout package qui l'importe peut y
accéder. Cela signifie qu'elle est publique par défaut, sauf
si vous spécifiez un modificateur de visibilité. De même,
lorsque vous définissez ou déclarez des propriétés et des
méthodes dans la classe, elles sont accessibles par défaut
en dehors de la classe via l'objet de classe. Il est essentiel
de définir une visibilité appropriée pour le code,
principalement pour masquer les propriétés et les
méthodes auxquelles les autres classes ne doivent pas
accéder.
91
Les classes en Kotlin
Modificateurs de visibilité

Modificateurs de visibilité pour les propriétés

Modificateurs de visibilité pour méthodes

92
Les classes en Kotlin
Modificateurs de visibilité

Modificateurs de visibilité pour les classes

Modificateurs de visibilité pour les constructeurs

93
Les classes en Kotlin

Exercice :
- Ecrire un programme qui définit une classe Forme
avec un constructeur qui donne la valeur de la
hauteur(y) et de la largeur (x).
- Définir deux sous classes Rectangle et Triangle,
puis donner dans ces deux sous classes la méthode
area() qui calcule l’aire.
- Dans le programme principale main(), définissez un
triangle et un rectangle , puis appelez la fonction
area() dans ces deux variables.

94
Et Voilà !
C’est fini pour cette semaine, rendez-vous la séance prochaine pour
le cours sur les interfaces de l’utilisateur.

95
PROGRAMMATION
IMPÉRATIVE

KOTLIN + XML

96
SÉANCE 3

CONCEPTION
D’INTERFACES
D’UTILISATEUR
97
Le cours de cette semaine explique la création d’interfaces utilisateur :
• Activités
• Relations entre un source kotlin et des ressources
• Layouts et vues
On ne s’intéresse qu’à la mise en page. L’activité des interfaces sera étudiée la
semaine prochaine.
98
Présentation des concepts
Composition d’une application

L’interface utilisateur d’une application Android est composée d’écrans.


Un « écran » correspond à une activité.
Exemples : afficher des informations, éditer des informations
Les dialogues et les pop-up ne sont pas des activités, ils se superposent
temporairement à l’écran d’une activité.
L’interface d’une activité est composée de vues :
❑ Vues élémentaires : boutons, zones de texte, cases à cocher. . .
❑ Vues de groupement qui permettent l’alignement des autres vues :
lignes, tableaux, onglets, panneaux à défilement. . .
Chaque vue d’une interface est gérée par un objet Kotlin ou Java,
comme en Java classique, avec AWT, Swing ou JavaFX.

99
Présentation des concepts
Création d’une interface

Les objets d’interface pourraient être créés manuellement, mais :


❑ c’est très complexe, car il y a une multitude de propriétés à définir,
❑ ça ne permet pas de localiser, c’est à dire adapter une application à
chaque pays (sens de lecture de droite à gauche)
Alors, on préfère définir l’interface par l’intermédiaire d’un fichier XML
qui décrit les vues à créer. Il est lu automatiquement par le système
Android lors du lancement de l’activité et transformé en autant d’objets
Java ou kotlin qu’il faut.
Chaque objet kotlin est retrouvé grâce à un « identifiant de ressource ».

100
Présentation des concepts
Création d’un écran

Chaque écran est géré par une instance d’une sous-classe de Activity
que vous programmez. Il faut au moins surcharger la méthode
onCreate selon ce qui doit être affiché sur l’écran :
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContentView([Link].activity_main)
}
}

C’est l’appel setContentView(...) qui met en place l’interface. Son


paramètre est un identifiant de ressource, c’est-à-dire d’une disposition
de vues d’interface. C’est ce qu’on va étudier maintenant

101
Les ressources
Définition

❑ Les ressources sont tout ce qui n’est pas programme dans une
application.
❑ Dans Android, ce sont les textes, messages, icones, images, sons,
interfaces, styles, etc.
Comme il va y avoir de très nombreux identifiants dans une application :
✓ chaque vue possède un identifiant (si on veut)
✓ chaque image, icone possède un identifiant
✓ chaque texte, message possède un identifiant
✓ chaque style, theme, etc. etc.
Ils ont tous été regroupés dans une classe spéciale appelée R
Cette classe R est générée automatiquement par ce que vous mettez
dans le dossier res : interfaces, menus, images, chaînes. . . Certaines de
ces ressources sont des fichiers XML, d’autres sont des images PNG.
102
Les ressources
Rappel sur la structure d’un fichier XML

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


<racine xmlns:exemple="[Link]
<!-- commentaire -->
<element attribut1="valeur1" attribut2="valeur2">
<feuille1 exemple:attribut3="valeur3"/>
<feuille2>texte</feuille2>
</element>
texte en vrac
</racine>

103
Les ressources
Ressources de type chaînes

❑ Dans res/values/[Link], on place les chaînes de l’application,


au lieu de les mettre en constantes dans le code source :
❑ Intérêt : pouvoir traduire une application sans la recompiler
<resources>
<string name="app_name">My First Application</string>
<string name="message">Hello World!</string>
<string name="main_menu">Principal Menu </string>
</resources>
❑ Il est possible de traduire des ressources du type texte en plusieurs
autres langues. Lorsque les textes sont définis dans
res/values/[Link], il suffit de faire des copies du dossier
values, en values-us, values-fr, values-de, etc en fonction de la
langue et de traduire les textes en gardant les attributs name.

104
Les ressources
Ressources de type chaînes

❑ Dans un programme Kotlin, on peut très facilement placer un texte


dans une vue de l’interface :

val tv: TextView = findViewById<TextView>([Link]) // ...


nous y reviendrons
[Link]([Link])

❑ [Link] désigne le texte de <string name="Hello world !


">... dans le fichier res/values*/[Link]
❑ Par contre, si on veut récupérer l’une des chaînes des ressources
pour l’utiliser dans le programme, c’est un peu plus compliqué :

val texte:String =[Link]([Link])

105
Les ressources
Ressource de type texte

❑ Maintenant, dans un fichier de ressources décrivant une interface, on


peut également employer des ressources texte :

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cours" />

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Cours Dev App Mob" />

106
Les ressources
Ressource de type image

❑ De la même façon, les images PNG placées dans res/drawable et


res/mipmaps-* sont référençables :

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/logo_skool"
android:contentDescription="@string/app_name"
/>
❑ La notation @drawable/nom référence l’image portant ce nom dans
l’un des dossiers.
❑ NB: les dossiers res/mipmaps-* contiennent la même image à des
définitions différentes, pour correspondre à différents téléphones et
tablettes. Ex: mipmap-hdpi contient des icônes en 72x72 pixels.

107
Les ressources
Ressource de type tableau de chaine

❑ Identifiable par [Link]. On les places dans le fichier


res/values/[Link]. Voici un extrait du fichier.
<resources>
<string-array name="planetes">
<item>Mercure</item>
<item>Venus</item>
<item>Terre</item>
<item>Mars</item>
</string-array>
</resources>

❑ Dans le programme Kotlin, il est possible de faire :

val planets : Array <String> = [Link]([Link])

108
Les ressources
Ressource de type tableau de chaine

D’autres notations existent :


❑ @style/nom pour des définitions de res/style
❑ @menu/nom pour des définitions de res/menu
Certaines notations, @package:type/nom font référence à des données
prédéfinies, comme :
❑ @android:style/[Link]
❑ @android:color/black
Il y a aussi une notation en ?type/nom pour référencer la valeur de
l’attribut nom, ex : ?android:attr/textColorSecondary.

109
Mise en page (layouts)
Structure d’une interface Android

Un écran Android de type formulaire est généralement composé de


plusieurs vues. Entre autres :
❑ TextView, ImageView : titre, image
❑ EditText : texte à saisir
❑ Button, CheckBox : bouton à cliquer, case à cocher
Ces vues sont alignées à l’aide de groupes sous-classes de ViewGroup,
éventuellement imbriqués :
❑ LinearLayout : positionne ses vues en ligne ou en colonne
❑ RelativeLayout, ConstraintLayout : positionnent leurs vues l’une
par rapport à l’autre
❑ TableLayout : positionne ses vues sous forme d’un tableau

110
Mise en page (layouts)
Arbre de vue

Les groupes et vues forment un arbre.

111
Mise en page (layouts)
Arbre de vue

Exercice : Dessiner l’arbre de vue des interfaces ci-dessous.

112
Mise en page (layouts)
Ressource de type Layout

L’interface est stocké dans un fichier res/layout/[Link] qui est


référencé par son identifiant [Link].nom_du_fichier (donc ici c’est
[Link].activity_main) dans le programme kotlin :

override fun onCreate(savedInstanceState: Bundle?) {


[Link](window, false)
[Link](savedInstanceState)
setContentView([Link].activity_main)
}

La méthode setContentView fait afficher le layout indiqué.

113
Mise en page (layouts)
Identifiant et vues

Lorsque l’application veut manipuler l’une de ses vues, elle doit utiliser
[Link].
La notation @+id/nom définit un identifiant pour une vue.
Exemple :
Avec la définition suivante dans res/layout/[Link] :
<LinearLayout ...>
<TextView
android:id="@+id/message"
android:text="@string/bonjour" />
</LinearLayout>

var tv = findViewById<TextView>([Link])

114
Mise en page (layouts)
Identifiant et vues

Remarques :
Dans les fichiers [Link], il y a deux notations à ne pas confondre :
▪ @+id/nom pour définir (créer) un identifiant
▪ @id/nom pour référencer un identifiant déjà défini ailleurs
Exemple, le Button btn se place sous le TextView titre :
<RelativeLayout xmlns:android="..." ... >
<TextView ...
android:id="@+id/titre"
android:text="@string/titre" />
<Button ...
android:id="@+id/btn"
android:layout_below="@id/titre"
android:text="@string/ok" />
</RelativeLayout>

115
Mise en page (layouts)
Paramètres de positionnement
La plupart des groupes utilisent des paramètres de taille et de placement
sous forme d’attributs XML. Par exemple, telle vue à droite de telle autre,
telle vue la plus grande possible, telle autre la plus petite. Ces paramètres
sont de deux sortes :
❑ Ceux qui sont obligatoires pour toutes les vues :
▪ android:layout_width : largeur de la vue
▪ android:layout_height : hauteur de la vue
Ils peuvent valoir :
▪ "wrap_content" : la vue prend la place minimale
▪ "match_parent" : la vue occupe tout l’espace restant
▪ "valeurdp" : une taille fixe, ex : "100dp" mais c’est peu
recommandé, sauf 0dp pour un cas particulier.
Les dp sont une unité de taille indépendante de l’écran. 100dp font 100
pixels sur un écran de 160 dpi tandis qu’ils font 200 pixels sur un écran
320 dpi 116
Mise en page (layouts)
Paramètres de positionnement

❑ Ceux qui sont demandés par le groupe englobant et qui en


sont spécifiques comme :
▪ android:layout_weight
▪ android:layout_alignParentBottom
▪ android:layout_centerInParent.

117
Mise en page (layouts)
Autres paramètres géométriques

Il est possible de modifier l’espacement des vues :


❑ Padding espace entre le texte et les bords, géré par chaque vue
❑ Margin espace autour des bords, géré par les groupes
On peut définir les marges et les remplissages séparément sur chaque
bord (Top, Bottom, Left, Right), ou identiquement sur tous :
<Button
android:layout_margin="10dp"
android:layout_marginTop="15dp"
android:padding="10dp"
android:paddingLeft="20dp"
/>

118
Mise en page (layouts)
Groupes des vues LinearLayout

Il range ses vues soit horizontalement, soit verticalement. Il faut


seulement définir l’attribut android:orientation à "horizontal" ou
"vertical".
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:text="Ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<Button
android:text="Annuler"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout> 119
Mise en page (layouts)
Groupes des vues LinearLayout

Orientation = vertical Orientation = horizontal

120
Mise en page (layouts)
Groupes des vues TableLayout

C’est une variante du LinearLayout : les vues sont rangées en lignes de


colonnes bien alignées. Il faut construire une structure XML comme
celle-ci :
<TableLayout ...>
<TableRow>
<vue 1.1 .../>
<vue 1.2 .../>
</TableRow>

<TableRow>
<vue 2.1 .../>
<vue 2.2 .../>
</TableRow>
<TableLayout>
- Les <TableRow> n’ont aucun attribut.
- Ne pas spécifier android:layout_width dans les vues d’un TableLayout, car
c’est obligatoirement toute la largeur du tableau. Seul la balise <TableLayout>
exige cet attribut. 121
Mise en page (layouts)
Groupes des vues RelativeLayout

C’est le plus complexe à utiliser mais il donne de bons résultats. Il


permet de spécifier la position relative de chaque vue à l’aide de
paramètres complexes : (LayoutParams)
• Tel bord aligné sur le bord du parent ou centré dans son parent :
android:layout_alignParentTop, android:layout_centerVertical. . .
• Tel bord aligné sur le bord opposé d’une autre vue :
android:layout_toRightOf, android:layout_above,
android:layout_below
• Tel bord aligné sur le même bord d’une autre vue :
android:layout_alignLeft, android:layout_alignTop. . .
Pour bien utiliser un RelativeLayout, il faut :
- Commencer par définir les vues qui ne dépendent que des bords du
Layout : celles qui sont collées aux bords ou centrées.
- Puis créer les vues qui dépendent des vues précédentes.
122
Composantes d’interfaces
Les vues

Vue Rôle

TextView Insérer du texte

ImageView Insérer l’image

Button Créer le bouton

EditText Insérer une zone de saisie de texte

Chekbox Créer de cases à cocher.

SearchView Insérer une barre de recherche

123
Mise en page (layouts)
Arbre de vue

Exercice : Coder les interfaces suivantes

124
Et Voilà !
C’est fini pour cette semaine, rendez-vous la séance prochaine pour
le cours sur Vie d’une application.

125
SEMAINE 4

VIE D’UNE
APPLICATION
126
Le cours de cette semaine concerne la vie d’une application :
• Applications et activités, manifeste
• Cycles de vie
• Vues, événements et écouteurs.

127
Application et activités
Présentation

❑ Une application est composée d’une ou plusieurs activités.


Chacune gère un écran d’interaction avec l’utilisateur et est
définie par une classe Kotlin.
❑ Les vues d’une activité (boutons, menus, actions) permettent
d’aller sur une autre activité. Le bouton back permet de
revenir sur une précédente activité. C’est la navigation
entre activités.
❑ Une application complexe peut aussi contenir :
• des services : ce sont des processus qui tournent en
arrière-plan,
• des fournisseurs de contenu : ils représentent une
sorte de base de données (contacts,. . . ),
• des récepteurs d’annonces : pour gérer des messages
envoyés d’une application à une autre (notifications,…)
128
Application et activités
Déclaration d’une application et démarrage d’application

❑ Le fichier [Link] déclare les éléments d’une


application

❑ Une activité qui n’est pas déclarée dans le manifeste ne peut


pas être lancée.

❑ L’une des activités est marquée comme étant démarrable de


l’extérieur, grâce à un sous-élément <intent-filter>

❑ Un <intent-filter> déclare les conditions de démarrage d’une


activité. Celui-ci indique l’activité principale, celle qu’il faut
lancer quand on clique sur son icône.

129
Application et activités
Démarrage d’une activité et Intents

Les activités sont démarrées à l’aide d’intents. Un Intent


contient une demande destinée à une activité, par exemple,
composer un numéro de téléphone ou lancer l’application.

❑ action : spécifie ce que l’Intent demande. Il y en a de


très nombreuses :
❑ VIEW pour afficher quelque chose, EDIT pour
modifier une information, SEARCH. . .
❑ données : selon l’action, ça peut être un numéro de
téléphone, l’identifiant d’une information. . .
❑ catégorie : information supplémentaire sur l’action,
par exemple, ...LAUNCHER pour lancer une
application.

130
Application et activités
Démarrage d’une activité et Intents

Une application a la possibilité de lancer certaines activités


d’une autre application, celles qui ont un intent-filter.

Soit une seconde application dans le package


[Link]. Une activité peut la lancer ainsi
:
val intent = Intent(Intent.ACTION_MAIN)
[Link](Intent.CATEGORY_LAUNCHER)
[Link]("[Link]",
"[Link]. .MainActivity")
[Link] = Intent.FLAG_ACTIVITY_NEW_TASK startActivity(intent)

Cela consiste à créer un Intent d’action MAIN et de catégorie


LAUNCHER pour la classe MainActivity de l’autre application
131
Application et activités
Démarrage d’une activité et Intents

Soit une application contenant deux activités : Activ1 et


Activ2. La première lance la seconde par :
val intent = Intent(this, Activ2::[Link])
startActivity(intent)
• L’instruction startActivity démarre Activ2. Celle-ci se met au
premier plan, tandis que Activ1 se met en sommeil.
• Activ1 reviendra au premier plan quand Activ2 se finira ou
quand l’utilisateur appuiera sur back.

Ce bout de code est employé par exemple lorsqu’un bouton, un


menu, etc. est cliqué. Seule contrainte : que ces deux activités
soient déclarées dans [Link].

132
Application et activités
Démarrage d’une activité et Intents

133
Application et activités
Les autorisations d’une application

Une application doit déclarer les autorisations dont elle a besoin


: accès à internet, caméra, carnet d’adresse, GPS, etc. Cela se
fait en rajoutant des éléments dans le manifeste :

Consulter cette page pour les permissions :


[Link]
[Link]

134
Application et activités
Fonctionnement d’une application

Au début, le système Android lance l’activité qui est marquée


action=MAIN et catégorie=LAUNCHER dans
[Link]. Ensuite, d’autres activités peuvent être
démarrées. Chacune se met « devant » les autres comme sur
une pile. Deux cas sont possibles :
❑ La précédente activité se termine, on ne revient pas dedans.
Par exemple, une activité où on tape son login et son mot de
passe lance l’activité principale et se termine.
❑ La précédente activité attend la fin de la nouvelle car elle lui
demande un résultat en retour. Exemple : une activité de
type liste d’items lance une activité pour éditer un item quand
on clique longuement dessus, mais attend la fin de l’édition
pour rafraîchir la liste.

135
Application et activités
Navigation entre deux activités

❑ Rappel, pour lancer Activ2 à partir de Activ1 :


val intent = Intent(this, Activ2::[Link])
startActivity(intent)

❑ On peut demander la terminaison de this après lancement de


Activ2 ainsi :
val intent = Intent(this, Activ2::[Link])
startActivity(intent)
finish()
finish() fait terminer l’activité courante. L’utilisateur ne pourra
pas faire back dessus, car elle disparaît de la pile.

136
Application et activités
Terminaison d’une activité

L’activité lancée par la première peut se terminer pour deux


raisons :

❑ Volontairement, en appelant la méthode finish()


❑ À cause du bouton « back » du téléphone

Dans ces deux cas, on revient dans l’activité appelante (sauf si


elle-même avait fait finish().

137
Application et activités
Transport d’informations dans un Intent

Les Intents servent aussi à transporter des informations d’une


activité à l’autre : les extras.
Voici comment placer des données dans un Intent :
val intent = Intent(this, DeleteInfoActivity::[Link])
[Link]("idInfo", idInfo)
[Link]("hiddencopy", hiddencopy)
startActivity(intent)

putExtra(nom, valeur) rajoute un couple (nom, valeur) dans


l’intent. La valeur doit être sérialisable : nombres, chaînes et
structures simples.

138
Application et activités
Extractions d’informations dans un Intent

Ces instructions récupèrent les données d’un Intent :


val OTP = [Link]("OTP").toString()
val PhoneNumber = [Link]("phoneNumber")

• intent retourne l’Intent qui a démarré cette activité.


• getTypeExtra(nom, valeur par défaut) retourne la valeur
de ce nom si elle en fait partie, la valeur par défaut sinon.

139
Application et activités
Contexte d’application

Pour finir sur les applications, il faut savoir qu’il y a un objet


global vivant pendant tout le fonctionnement d’une application :
le contexte d’application. Voici comment le récupérer :

var context: Application = [Link] as Application

Par défaut, c’est un objet neutre ne contenant que des


informations Android.
Il est possible de le sous-classer afin de stocker des variables
globales de l’application.

140
Activités
Présentation

Voyons maintenant comment fonctionnent les activités.


❖ Démarrage (à cause d’un Intent)
❖ Apparition/masquage sur écran
❖ Terminaison

Une activité se trouve dans l’un de ces états :


❑ active (resumed) : elle est sur le devant, l’utilisateur peut
jouer avec,
❑ en pause (paused) : partiellement cachée et inactive, car
une autre activité est venue devant,
❑ stoppée (stopped) : totalement invisible et inactive, ses
variables sont préservées mais elle ne tourne plus.

141
Activités
Cycle de vie d’une activité

142
Activités
Événements de changement d’état

La classe Activity reçoit des événements de la part du système


Android, ça appelle des fonctions appelées callbacks.
Exemples :
• onCreate : Un Intent arrive dans l’application, il déclenche la
création d’une activité, dont l’interface.
• onPause : Le système prévient l’activité qu’une autre activité
est passée devant, il faut enregistrer les informations au cas
où l’utilisateur ne revienne pas.

143
Activités
Squelette d’une activité

class sign_in : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_sign_in)
}

Override signifie que cette méthode remplace celle héritée de


la superclasse. Il faut quand même
l’appeler sur super en premier.

144
Vues et activités
Obtention des vues

La méthode setContentView charge une mise en page


(layout) sur l’écran. Ensuite l’activité peut avoir besoin d’accéder
aux vues, par exemple lire la chaîne saisie dans un texte. Pour
cela, il faut obtenir l’objet Kotlin correspondant.

val btn :Button = findViewById([Link].btn_confimer)


val code: TextView = findViewById([Link])

Cette méthode cherche la vue qui possède cet identifiant dans


le layout de l’activité. Si cette vue n’existe pas (mauvais
identifiant, ou pas créée), la fonction retourne null.

145
Vues et activités
Propriétés des vues

La plupart des vues ont des setters et getters Kotlin pour leurs
propriétés XML. Par exemple TextView.
En XML :
<TextView
android:id="@+id/PwdForgetId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mot de passe oublié ?"
/>
En Kotlin
val text_pwd: TextView = findViewById([Link]. PwdForgetId)
text_pwd.text ="Mot de passe oublié ?"
146
Vues et activités
Actions de l’utilisateur

Il y’a deux façons de définir l’action d’un utilisateur sur une vue:
❑ on peut procéder directement dans le fichier xml de la vue
en insérant l’attribut onClick()

Pour cet exemple, Lorsque l’utilisateur appuie sur le bouton, ça


appelle automatiquement la méthode onValider de l’activité
grâce à l’attribut onClick="onValider".

Il faut définir la méthode onValider dans l’activité : 147


Vues et activités
Actions de l’utilisateur

fun onValider(view: View) {


// votre code ici
}

❑ La deuxième façon de définir une réponse à un clic est de


définir un écouteur (listener).

Un écouteur est une instance de classe implémentant


l’interface [Link] qui possède la méthode
public void onClick(View v)

148
Vues et activités
Actions de l’utilisateur

Exemple d’écouteur sur le bouton

val btn :Button = findViewById([Link].btn_onValider)


[Link]([Link] {

onValider()
}
)

fun onValider(view: View) {


// votre code ici
}

149
Vues et activités
Actions de l’utilisateur

L’exemple précèdent est un écouteur privé. Il s’agit d’une classe


qui est définie à la volée, lors de l’appel à setOnClickListener.
Elle ne contient qu’une seule méthode.
Il est intéressant de transformer cet écouteur en expression
lambda qui une fonction sans nom écrite ainsi :

(paramètres avec ou sans types) -> expression


(paramètres avec ou sans types) -> { corps }

Cette transformation de l’écouteur est possible parce que


l’interface [Link] ne possède qu’une seule
méthode. On parle alors d’écouteur privé anonyme

150
Vues et activités
Actions de l’utilisateur

Exemple :

[Link] { btn: View? ->


//code ici
}
Il existe une autre façon de définir un écouteur: L’activité elle-
même en tant qu’écouteur. Il suffit de mentionner this comme
écouteur et d’indiquer qu’elle implémente l’interface
OnClickListener.

L’exemple est donné ci-dessous:


151
Vues et activités
Actions de l’utilisateur

Exemple :
class HomeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContentView([Link].activity_home)

[Link](this)
}

fun OnClickListener(btn : View?){

Ici, par contre, tous les boutons appelleront la même méthode.


152
Vues et activités
Actions de l’utilisateur

fun OnClickListener(v:View){
Dans le cas où le même
when ([Link]) {
écouteur est employé [Link] -> {
pour plusieurs vues, il supprimer()
faut les distinguer en true
se basant sur leur }
identifiant obtenu avec [Link] -> {
Id : modifier()
true
}
else -> {
// autres methodes
true
}
}
}
153
Vues et activités
Actions de l’utilisateur

Il y a une dernière façon très pratique d’associer un écouteur,


avec une référence de méthode, c’est à dire son nom précédé
de l’objet qui la définit.
class HomeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContentView([Link].activity_home)

[Link](this::OnBtnClick)
}

fun OnBtnClick(btn : View?){

}
La syntaxe this::nom_methode est une simplification de
l’expression lambda (params) -> nom_methode(params) 154
Exercice
Description:
Cet exercice est une simple application Android avec trois
activités, la première activité est l'activité principale avec deux
boutons. Bouton 1 : vous amène à l'activité B lorsque vous cliquez
dessus. Bouton 2 : vous amène à l'activité C lorsque vous cliquez
dessus.
Activité B : est la page contenant un formulaire de connexion
destiné à collecter les informations suivantes: login, mot de passe
et contient deux boutons (connexion et annuler). En cliquant sur
le bouton connexion , l’utilisateur est redirigé vers la page A en
affichant le message « Connexion reussite » si les informations ne
sont pas vides. Sinon afficher un message pour lui demander de
renseigner les informations
L'activité C est votre profil, elle contient une ImageView qui
devrait afficher votre photo, TextViews indiquant votre nom,
piste, pays, e-mail et numéro de téléphone. 155
Exercice

156
Et Voilà !
C’est fini pour aujourd’hui. C’est assez pour cette semaine, rendez-
vous la semaine prochaine pour un cours sur les applications listes.

157
SÉANCE 5

APPLICATION
LISTE
158
Durant cette semaine prochaine, nous allons nous intéresser aux
applications de gestion d’une liste d’items.
• Stockage d’une liste
• Affichage d’une liste, adaptateurs
• Consultation et édition d’un item
159
Présentation
Principe général

❑ On veut programmer une application pour afficher et éditer


une liste d’items.
❑ La liste est stockée dans un tableau type ArrayList
❑ L’écran est occupé par un Listview ou RecyclerView. Ce
sont des vues spécialisées dans l’affichage de listes
quelconques.
❑ Il existe deux façon de faire des listes dans Android avec
Kotlin :
❑ Liste simple (basé sur les adaptateurs simples) : On utilise
Listview
❑ Liste personnalisée (basée sur les adaptateurs
personnalisé ) : On utilise RecyclerView

160
Présentation
Principe général

Définition
Android ListView est une vue utilisée pour afficher les
éléments d'un tableau sous forme de liste défilante.

161
Présentation
Principe général

Liste simple Liste personnalisée 162


Présentation
Schéma global

❑ Modèle MVC : le contrôleur entre les données et la vue


s’appelle un adaptateur.

ArrayList ListView
RecyclerView
163
Présentation
Représentation des données initiales

❑ Pour commencer, il faut représenter les données :


▪ Utiliser les classes pour une liste personnalisée avant de
stocker les données dans un ArrayList
▪ Pas besoin des classes pour une liste simple. On peut
directement stocker les données initiales dans un tableau.
//création de la classe Personne
class Personne (var Age:Int, var Nom:String) {
}
// création des instances de Personne
val P1=Personne (12,Banane)
val P2=Personne (22,INFO)

// création d’une liste de noms des Personnes


val ListePersonne : ArrayList<Personne>
var ListePersonne = arrayOf([Link], [Link])
164
Présentation
Représentation des données initiales

NB: ArrayList Crée une liste non modifiable.


C’est un type de données générique, c’est à dire paramétré par
le type des éléments mis entre <. . . > ; ce type doit être un
objet (String, Int, Classe, …).
Quelques méthodes utiles de la classe abstraite List, héritées
par ArrayList :
Méthodes fonctions
[Link]() retourne le nombre d’éléments présents,
[Link]() supprime tous les éléments
[Link](elem) : ajoute cet élément à la liste,
[Link](elem ou indice) : retire cet élément
[Link](indice) : retourne l’élément présent à cet indice,
[Link](elem) : true si elle contient cet élément,
[Link](elem) : indice de l’élément, s’il y est 165
Présentation
Représentation des données initiales dans les ressources

On crée deux tableaux dans le fichier res/values/[Link] :

<resources>
<string-array name="Noms">
<item>Jean</item>
<item>Abbas</item>
...
</string-array>
<integer-array name="Age">
<item>18</item>
<item>108</item>
...
</integer-array>
</resources>

166
Présentation
Représentation des données initiales dans les ressources

Ensuite, on récupère ces ressources tableaux pour remplir le


ArrayList :
// accès aux ressources
// accès aux ressources
val res: Resources = resources
val noms: Array<String> = [Link]([Link])
val ages: IntArray = [Link]([Link])
// recopie dans le ArrayList
liste = ArrayList()
for (i in [Link]) {
[Link](Personne(noms[i], ages[i]))
}
Ça semble plus complexe, mais c’est préférable à la solution du tableau
pré-initialisé pour la séparation entre programme et données
167
Affichage de la liste
Activité

L’affichage de la liste est fait par un ListView ou


RecyclerView. Ce sont des vues qui intègre un défilement
automatique et qui veille à économiser la mémoire pour
l’affichage.
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<[Link]
xmlns:android="[Link]
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent" />

168
Adaptateurs et ViewHolders
Relations entre la vue et les données

ListView ou RecyclerView affiche les items d’une liste à l’aide


d’un adaptateur :

169
Adaptateurs et ViewHolders
Adaptateur pour une liste simple

❑ On utilise un ArrayAdapter (qui est un adaptateur de


tableau) pour une afficher une liste simple.
❑ Initialisez ArrayAdapter avec le contexte d'application, la
ressource (layout des items) à utiliser comme vue pour
chaque élément de la liste et le tableau d'éléments lui-même
comme arguments.
❑ Définissez l'adaptateur créé à l'étape précédente sur ListView.

170
Adaptateurs et ViewHolders
Adaptateur pour une liste simple

//création d’un adaptateur de tableau


val adapter = ArrayAdapter(this,[Link].listview_item, array)

//Référencement de Listview à utiliser


val listView : ListView = findViewById([Link])

//définission de l’adapteur sur Listview


[Link](adapter)

171
Adaptateurs et ViewHolders
Adaptateur pour une liste simple

Exercice
Créer une application Android qui affiche la liste des 10
pays africains de votre choix.

NB: utilisez une liste simple.

172
Adaptateurs et ViewHolders
RecyclerView

Définition
RecyclerView est un widget d'affichage de liste avancé
disponible dans la bibliothèque de support d'Android. Il
permet de gérer de grandes quantités de données de
manière efficace en réutilisant les éléments de la liste qui
ne sont plus visibles pour économiser les ressources de la
mémoire.
Il offre une flexibilité et une personnalisation accrues par
rapport à la ListView, qui était le widget d'affichage de
liste standard dans les versions antérieures d'Android. Le
RecyclerView peut être utilisé pour afficher une liste
verticale, horizontale ou en grille, avec des mises en forme
personnalisées pour chaque élément de la liste.
173
Adaptateurs et ViewHolders
RecyclerView

❑ La vue ne sert qu’à afficher les éléments de la liste. En


réalité, seuls quelques éléments seront visibles en même
temps. Cela dépend de la hauteur de la liste et la hauteur
des éléments.
❑ Le principe du RecyclerView est de ne gérer que les
éléments visibles. Ceux qui ne sont pas visibles ne sont pas
mémorisés. Mais lorsqu’on fait défiler la liste ainsi qu’au
début, de nouveaux éléments doivent être rendus visibles.
❑ Le RecyclerView demande alors à l’adaptateur de lui
instancier (inflate) les vues pour afficher les éléments.
❑ Le nom « RecyclerView » vient de l’astuce : les vues qui
deviennent invisibles à cause du défilement vertical sont
recyclées et renvoyées de l’autre côté mais en changeant
seulement le contenu à afficher. 174
Adaptateurs et ViewHolders
Adaptateur pour une liste personnalisée : RecyclerView

❑ Une vue qui devient invisible d’un côté, à cause du scrolling,


est renvoyée de l’autre côté, comme sur un tapis roulant,
en modifiant seulement son contenu : Il économise de la
mémoire en réutilisant les vues lorsque vous faites défiler
une activité au lieu de les créer toutes au début lors du
premier chargement de l'activité.

175
Adaptateurs et ViewHolders
Adaptateur pour une liste personnalisée : RecyclerView

❑ RecyclerView comporte trois parties principales : la mise


en page, le ViewHolder et l'adaptateur.
❑ La mise en page est la vue qui sera créée pour chaque
élément à charger dans RecyclerView (Layout des items).
❑ Un ViewHolder est utilisé pour mettre en cache les objets
de vue afin d'économiser de la mémoire.
❑ L'adaptateur crée de nouveaux éléments sous la forme de
ViewHolders, remplit les ViewHolders avec des données et
renvoie des informations sur les données.
❑ Pour utiliser RecyclerView il faut ajouter la dépendance du
projet recyclerview-v7 dans le fichier [Link]
(Module : app).
implémentation '[Link]:recyclerview-v7:26.1.0'
176
Adaptateurs et ViewHolders
Adaptateur pour une liste personnalisée : RecyclerView

177
Adaptateurs et ViewHolders
La mise en page

Créez un layout pour chaque élément de la liste. Exemple :


planet_item.xml:
<LinearLayout xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/planetImage"
android:layout_width="50dp"
android:layout_height="50dp" />
<TextView
android:id="@+id/planetName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginStart="16dp" />
</LinearLayout>
178
Adaptateurs et ViewHolders
ViewHolder

❑ Créez une classe de base (par exemple Planète) pour


stocker les données pour chaque élément de la liste:

❑ Créez un Adapter pour le RecyclerView qui étendra


[Link]. Il va contenir la classe ViewHolder
qui est associée à une donnée de base, ex: une planète et
qui permet son affichage dans un RecyclerView.

179
Adaptateurs et ViewHolders
ViewHolder

❑ La classe ViewHolder contient les méthodes suivantes:


❑ onCreateViewHolde :méthode qui crée les
ViewHolder , Elle est appelée au début de l’affichage de
la liste, pour initialiser ce qu’on voit à l’écran.
inflate = transformer un fichier XML en vues Kotlin.
❑ getItemCount: Elle qui retourne le nombre d’éléments
❑ onBindViewHolder : méthode qui recycle les
ViewHolder . Cette méthode est appelée pour remplir un
ViewHolder avec l’un des éléments de la liste, celui qui
est désigné par position (numéro dans la liste à l’écran).
C’est très facile avec le setter.

180
Adaptateurs et ViewHolders
ViewHolder
class PlanetAdapter(private val planets: List<Planet>) :
[Link]<[Link]>() {

class ViewHolder(itemView: View) : [Link](itemView) {


fun bind(planet: Planet) {
[Link] = [Link]
[Link]([Link])
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {


val view = [Link]([Link])
.inflate([Link].planet_item, parent, false)
return ViewHolder(view)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {


[Link](planets[position])
}

override fun getItemCount() = [Link]


181
}
Adaptateurs et ViewHolders
Définition de l’adaptateur

❑ Ajoutez le RecyclerView à votre layout principal et


définissez l'Adapter:
<[Link]
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

val planets = listOf(


Planet("Mercury", [Link]),
Planet("Venus", [Link]),
Planet("Earth", [Link]),
// ...
)

val adapter = PlanetAdapter(planets)


[Link] = adapter
[Link] = LinearLayoutManager(this)

182
Adaptateurs et ViewHolders
Définition de l’adaptateur

Exercice
Refaire la liste de l’application précédente, on insérant
cette fois ci dans la liste le nom du pays suivi de son
drapeau et ainsi que sa zone. L’exemple est donné ci-
dessous:
Cameroun
Afrique centrale

183
Actions sur la liste
Clic sur un élément

❑ Avec ce qui précède, la liste s’affiche automatiquement. On


s’intéresse maintenant à un clic sur un élément de la liste.
Dans Android, rien n’est prévu pour les clics sur les
éléments. On doit construire soi-même une architecture
d’écouteurs.

Voici d’abord la situation, pour comprendre la solution :


❑ 1. L’activité MainActivity veut être prévenue quand
l’utilisateur clique sur un élément de la liste.
❑ 2. L’objet qui reçoit les événements utilisateur est le
ViewHolder. Il lui suffit d’implémenter la méthode
onClick(View v) de l’interface [Link] comme
un simple Button pour être prévenu d’un clic sur lui.
184
Actions sur la liste
Clic sur un élément

❑ 3. Un RecyclerView regroupe plusieurs ViewHolder ; chacun


peut être cliqué (un à la fois). Celui qui est cliqué peut faire
quelque chose, mais son problème, c’est qu’il ne connaît
pas l’activité. Il faut donc faire le lien entre ces ViewHolder
et l’activité. Ça va passer par l’adaptateur, le seul qui soit au
contact des deux.
1. Il faut que l’activité définisse un écouteur de clics et le
fournisse à l’adaptateur. Tant qu’à faire, on peut définir notre
propre sorte d’écouteur qui recevra la position de l’objet cliqué
en paramètre (c’est le plus simple à faire).
2. L’adaptateur transmet cet écouteur à tous les ViewHolder
qu’il crée ou recycle.
3. Chaque ViewHolder possède donc cet écouteur et peut le
déclencher le cas échéant. 185
Actions sur la liste
Clic sur un élément

186
Actions sur la liste
Définition d’un écouteur de clic

❑ utiliser un OnClickListener dans votre ViewHolder:

class ViewHolder(itemView: View) : [Link](itemView) {


fun bind(planet: Planet) {
[Link] = [Link]
[Link]([Link])
[Link] {
// traitement lors du clic sur un élément de la liste
}
}
}

187
Actions sur la liste
Définition d’un écouteur de clic

On récupère ici le numéro de l’élèment dans la liste


class ViewHolder(itemView: View) : [Link](itemView), [Link] {
fun bind(planet: Planet) {
[Link] = [Link]
[Link]([Link])
[Link](this)
}

override fun onClick(v: View?) {


val position = adapterPosition
[Link](v?.context, "Element $position cliqué", Toast.LENGTH_SHORT).show()
}
}

188
Actions sur la liste
Définition d’un écouteur de clic

Exercice
Modifier la liste précédente de telle sorte que le nom du
pays et son numéro dans la liste puisse etre afficher à
l’utilisateur après avoir cliqué dessus.

189
Ouf, c’est fini !
C’est tout pour cette séance. La séance prochaine nous parlerons des
menus, dont les menus contextuels qui apparaissent quand on clique
longuement sur un élément d’une liste, dialogues et fragments

190
SÉANCE 6

ERGONOMIE

191
Le cours de cette séance concerne l’ergonomie d’une application
Android.
• Menus et barre d’action
• Pop-up : messages et dialogues
• Activités et fragments
• Préférences (pour info)
192
Barre d’action et menus
Barre d’action

❑ La barre d’action contient l’icône et le nom de d’application,


quelques items de menu et un bouton pour avoir les autres
menus .

193
Barre d’action et menus
Le menu

❑ Un menu est une liste de d’items présentés dans la barre


d’action. La sélection d’un item déclenche une callback.

❑ Pour créer un menu sous Android, il faut définir :


- un fichier res/menu/nom_du_menu.xml qui est une sorte
de layout spécialisé pour les menus,

- deux méthodes d’écouteur pour gérer les menus :


❑ ajout du menu dans la barre,
❑ activation de l’un des items.

194
Barre d’action et menus
Le menu

❑ Exemple de fichier [Link]


<menu xmlns:android="[Link]
<item
android:id="@+id/menu_item_1"
android:title="Menu Item 1"
android:icon="@drawable/ic_menu_item_1"
android:showAsAction="ifRoom" />
<item
android:id="@+id/menu_item_2"
android:title="Menu Item 2"
android:icon="@drawable/ic_menu_item_2"
android:showAsAction="ifRoom" />
<item
android:id="@+id/menu_item_3"
android:title="Menu Item 3"
android:icon="@drawable/ic_menu_item_3"
android:showAsAction="never" />
</menu> 195
Barre d’action et menus
Le menu

L'attribut showAsAction définit comment une option de menu


doit être affichée dans l'interface utilisateur. Il peut avoir les
valeurs suivantes :
❑ always : l'option de menu sera toujours affichée en tant
qu'icône dans la barre d'actions.
❑ ifRoom : l'option de menu sera affichée en tant qu'icône dans
la barre d'actions si elle peut s'y insérer. Sinon, elle sera
affichée dans le menu déroulant.
❑ never : l'option de menu sera toujours affichée dans le menu
déroulant, jamais en tant qu'icône dans la barre d'actions.

Cet attribut est à modifier en app:showAsAction si on utilise


androidx.

196
Barre d’action et menus
Le menu : les icones

Android distribue gratuitement un grand jeu d’icônes pour les


menus, dans les deux styles MaterialDesign : HoloDark et
HoloLight.

197
Barre d’action et menus
Les écouteurs pour afficher les menus

Pour afficher un menu dans une activité Android en Kotlin, vous


pouvez utiliser la méthode onCreateOptionsMenu de votre
activité. Cette méthode est appelée lorsque le système crée le
menu pour la première fois. Vous pouvez y définir les options de
menu à afficher en utilisant la méthode [Link].
Voici un exemple de code pour créer un écouteur qui affiche un
menu :

override fun onCreateOptionsMenu(menu: Menu): Boolean {


// Inflate the menu; this adds items to the action bar if it is present.
[Link]([Link].main_menu, menu)
return true
}

198
Barre d’action et menus
Réactions aux sélections d’items

• Lorsqu'un utilisateur sélectionne une option de menu dans


votre application Android en Kotlin, vous pouvez réagir à cette
sélection en implémentant la méthode onOptionsItemSelected
de votre activité.

• Cette méthode est appelée lorsque l'utilisateur sélectionne


une option de menu et prend en entrée un objet MenuItem
qui représente l'option de menu sélectionnée.

199
Barre d’action et menus
Réactions aux sélections d’items
class MainActivity : AppCompatActivity() {
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
[Link]([Link].main_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle item selection
return when ([Link]) {
[Link].menu_item_1 -> {
// Action to perform when menu item 1 is selected
true
}
[Link].menu_item_2 -> {
// Action to perform when menu item 2 is selected
true
}
else -> [Link](item)
}
}
} 200
Barre d’action et menus
Menus en cascade

Les menus en cascade, ou sous-menus, permettent de


créer des niveaux supplémentaires dans un menu, pour
afficher des options supplémentaires ou des fonctionnalités
plus avancées.

Pour créer des menus en cascade dans une application


Android en Kotlin, vous pouvez utiliser l'élément <menu>
imbriqué à l'intérieur d'un autre élément <item> dans votre
fichier de menu XML. Voici un exemple de fichier XML pour
un menu en cascade :

201
Barre d’action et menus
Menus en cascade

<menu xmlns:android="[Link]
<item
android:id="@+id/menu_item_1"
android:title="Menu Item 1"
android:icon="@drawable/ic_menu_item_1"
android:showAsAction="ifRoom">
<menu>
<item
android:id="@+id/submenu_item_1"
android:title="Submenu Item 1"
android:icon="@drawable/ic_submenu_item_1" />
<item
android:id="@+id/submenu_item_2"
android:title="Submenu Item 2"
android:icon="@drawable/ic_submenu_item_2" />
</menu>
</item>
<item
android:id="@+id/menu_item_2"
android:title="Menu Item 2"
android:icon="@drawable/ic_menu_item_2"
android:showAsAction="ifRoom" />
</menu>
202
Barre d’action et menus
Menus contextuels

• Les menus contextuels (ou "menus contextuels") sont


des menus qui apparaissent dans une interface
graphique lorsqu'un utilisateur effectue un clic droit sur
un élément. Ces menus fournissent une liste d'options
contextuelles en fonction de l'élément sur lequel
l'utilisateur a cliqué.

203
Barre d’action et menus
Menus contextuels

Pour créer un menu contextuel en Kotlin, vous pouvez utiliser la


classe ContextMenu fournie par le framework Android. Voici les
étapes à suivre pour créer un menu contextuel dans une
application Android en Kotlin :
1. Créez une vue ou un widget pour lequel vous souhaitez créer
un menu contextuel.
2. Ajoutez un listener de clic droit à la vue ou au widget à l'aide
de la méthode setOnCreateContextMenuListener().
3. Dans le listener de clic droit, créez une instance de la classe
ContextMenu et ajoutez des éléments de menu à l'aide de la
méthode add().
4. Définissez un listener pour chaque élément de menu en
utilisant la méthode setOnMenuItemClickListener().
5. Affichez le menu contextuel à l'aide de la méthode show()
204
Barre d’action et menus
Menus contextuels

val myView = findViewById<View>([Link].my_view)

[Link] { menu, v, menuInfo ->


[Link]("Option 1")
[Link]("Option 2")
[Link]([Link].option1)?.setOnMenuItemClickListener {
// Code à exécuter lorsque l'option 1 est sélectionnée
true
}
[Link]([Link].option2)?.setOnMenuItemClickListener {
// Code à exécuter lorsque l'option 2 est sélectionnée
true
}
}

[Link] {
[Link]()
true
205
}
Barre d’action et menus
Menus contextuels

❑ Dans cet exemple, myView est la vue à laquelle le menu


contextuel est associé.
❑ Le listener setOnCreateContextMenuListener() crée le menu
contextuel et ajoute deux éléments de menu.
❑ Les listeners setOnMenuItemClickListener() définissent le code
à exécuter lorsque chaque élément de menu est sélectionné.
❑ Enfin, le listener setOnLongClickListener() affiche le menu
contextuel lorsque l'utilisateur effectue un clic long sur la vue.

206
Annonces et dialogues
Les annonces

Pour afficher une annonce (message d'information) à l'utilisateur


dans une application Android en utilisant la classe Toast de
Kotlin.

Un « toast » est un message apparaissant en bas d’écran pendant un


instant, par exemple pour confirmer la réalisation d’une action. Un toast
n’affiche aucun bouton et n’est pas actif.

Voici les étapes à suivre :

1. Importez la classe Toast dans votre fichier de code :


import [Link]

207
Annonces et dialogues
Les annonces

2. Utilisez la méthode makeText() de la classe Toast pour créer


une nouvelle instance de Toast en spécifiant le contexte de
l'application, le texte de l'annonce et la durée pendant laquelle
l'annonce doit être affichée (valeur de la constante
LENGTH_SHORT pour une courte durée et LENGTH_LONG pour
une durée plus longue) puis affichez l'annonce en appelant la
méthode show() de l'instance Toast : :

val message = "Ceci est une annonce"


val duration = Toast.LENGTH_SHORT
val toast = [Link](context, message, duration)
[Link]()

208
Annonces et dialogues
Les dialogues

• Les dialogues sont des fenêtres pop-up qui s'affichent au-


dessus de l'interface utilisateur principale d'une application
Android. Ils peuvent être utilisés pour afficher des messages
d'erreur, demander une confirmation de l'utilisateur ou pour
fournir des informations supplémentaires à l'utilisateur.

• Il existe plusieurs types de dialogues dans une application


Android :
1. Dialogue d’alerte
2. Dialogue de sélection
3. Dialogue de progression
4. Dialogues personnalisés

209
Annonces et dialogues
Les dialogues

• Dialogues d'alerte (AlertDialog) : ces dialogues sont utilisés


pour afficher des messages d'erreur, des avertissements ou des
messages d'information à l'utilisateur. Ils ont un titre, un
message et un ou plusieurs boutons pour l'utilisateur.

val builder = [Link](this)


[Link]("Confirmer l'action")
.setMessage("Voulez-vous vraiment effectuer cette action ?")
.setPositiveButton("OK") { dialog, which ->
// Code à exécuter lorsque l'utilisateur appuie sur le bouton OK
}
.setNegativeButton("Annuler") { dialog, which ->
// Code à exécuter lorsque l'utilisateur appuie sur le bouton Annuler
}
val dialog = [Link]()
[Link]()
210
Annonces et dialogues
Les dialogues

• Dialogues de sélection (Dialog) : ces dialogues sont utilisés


pour permettre à l'utilisateur de faire un choix parmi une liste
d'options. Ils ont généralement un titre, une liste de choix et des
boutons pour l'utilisateur.
val items = arrayOf("Option 1", "Option 2", "Option 3")
val builder = [Link](this)
[Link]("Sélectionnez une option")
.setItems(items) { dialog, which ->
// Code à exécuter lorsque l'utilisateur sélectionne une
option
}
val dialog = [Link]()
[Link]()
211
Annonces et dialogues
Les dialogues

• Dialogues de progression (ProgressDialog) : ces dialogues


sont utilisés pour afficher la progression d'une tâche ou d'une
opération en cours. Ils ont généralement un message qui décrit
la tâche en cours et une barre de progression pour indiquer la
progression.
val progressDialog = ProgressDialog(this)
[Link]("Please Wait")
[Link](« Preparing to download...")
[Link](false)
[Link]()

212
Annonces et dialogues
Les dialogues

• Dialogues personnalisés (DialogFragment) : ces dialogues


sont utilisés pour créer des dialogues personnalisés avec un
contenu et une apparence personnalisés. Ils peuvent contenir
des champs de texte, des boutons, des images ou tout autre
élément d'interface utilisateur.
class CustomDialogFragment : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Charger le fichier de mise en page personnalisé
val view = [Link]([Link].dialog_layout, container, false)

// Définir les listeners de bouton ou d'autres éléments d'interface utilisateur

return view
}
} 213
Annonces et dialogues
Les dialogues

Remarque:

Pour fermer un dialogue en Kotlin, vous pouvez appeler la méthode


dismiss() sur l'objet Dialog ou DialogFragment

214
Les fragments
Présentation

• Les fragments en Kotlin sont des éléments d'interface utilisateur


réutilisables qui peuvent être combinés pour créer des interfaces
utilisateur plus complexes.
• Les fragments sont similaires aux activités, mais contrairement
aux activités, ils ne peuvent pas être exécutés indépendamment.
• Les fragments doivent être intégrés à une activité hôte pour être
affichés.

215
Les fragments
Création de fragments en kotlin

• Pour créer un nouveau fragment en Kotlin, vous pouvez créer


une nouvelle classe qui étend la classe Fragment. Par exemple :
class MyFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflater le layout du fragment
Val view = [Link]([Link].my_fragment, container, false)
return view
}
}

216
Les fragments
Cycle de vie des fragments

• Les fragments ont un cycle de vie similaire à celui des activités,


avec quelques méthodes de plus correspondant à leur
intégration dans une activité.

217
Les fragments
Intégration de fragment à une activité
Pour ajouter un fragment à une activité hôte, vous devez ajouter
un FrameLayout à votre layout d'activité pour contenir le
fragment, puis utiliser FragmentManager pour ajouter le fragment à
ce conteneur. Par exemple :
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContentView([Link].activity_main)
// Ajouter le fragment
[Link]()
.add([Link].fragment_container, MyFragment())
.commit()
}
218
}
Les fragments
Communication entre Activité et Fragments

La communication entre une activité et un fragment peut se faire


de différentes manières en Kotlin.

1. Utilisation de l'interface :
Vous pouvez créer une interface dans votre fragment et
implémenter cette interface dans votre activité. Ensuite, vous
pouvez appeler la méthode de l'interface depuis votre fragment
pour communiquer avec votre activité.

Voici un exemple de code:

219
Les fragments
Communication entre Activité et Fragments

Dans le fragment
interface MyListener {
fun onButtonClick()
}

class MyFragment : Fragment() {


private var listener: MyListener? = null

override fun onAttach(context: Context) {


[Link](context)
listener = context as? MyListener
}

override fun onDetach() {


[Link]()
listener = null
}

fun onButtonClicked() {
listener?.onButtonClick()
}
}
220
Les fragments
Communication entre Activité et Fragments

Dans l’activité
class MyActivity : AppCompatActivity(), [Link] {

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_main)

val fragment = MyFragment()


[Link]()
.replace([Link].fragment_container, fragment)
.commit()
}

override fun onButtonClicked() {


// Faites quelque chose ici en réponse au clic sur le bouton dans le fragment
}
}

221
Les fragments
Communication entre Activité et Fragments

On peut aussi utiliser:

❑ Bundle : Vous pouvez ajouter des données à Bundle dans


votre activité, puis récupérer ces données dans votre fragment

❑ ViewModel pour partager des données entre votre activité et


votre fragment. ViewModel est un composant de l'architecture
Android qui permet de stocker et de gérer les données de
manière à survivre aux changements de configuration (par
exemple, lorsque l'écran est tourné)

222
Préférences d’application
Présentation

▪ Les préférences d'application sont importantes car elles


permettent aux utilisateurs de personnaliser l'expérience
utilisateur et de se sentir plus à l'aise en utilisant une application.
Les préférences peuvent inclure des paramètres tels que la
langue, la taille du texte, la couleur de fond, les notifications, etc.
Les utilisateurs ont souvent des préférences personnelles en
matière de conception et de fonctionnalité, et en permettant de
personnaliser les préférences, les applications peuvent répondre
aux besoins et aux préférences individuels des utilisateurs.
▪ Les développeurs peuvent également utiliser les préférences
d'application pour stocker les données de configuration, telles que
les paramètres de connexion ou les informations d'utilisateur, ce
qui peut améliorer l'expérience utilisateur en évitant à l'utilisateur
de saisir les mêmes informations plusieurs fois.
223
Préférences d’application
création de préférences

En Kotlin pour Android, vous pouvez définir les préférences


d'application en utilisant la classe SharedPreferences.
Voici un exemple de code pour créer et accéder aux préférences
d'application :
1. Créer un fichier de préférences xml: res/xml/[Link] :
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="[Link]
<PreferenceCategory android:title="Paramètres">
<CheckBoxPreference
android:key="notif_pref"
android:title="Activer les notifications"
android:defaultValue="true"/>
<ListPreference
android:key="lang_pref"
android:title="Langue"
android:entries="@array/langues"
android:entryValues="@array/langue_valeurs"
android:defaultValue="fr"/>
</PreferenceCategory>
</PreferenceScreen>
224
Préférences d’application
création et accès aux préférences

En Kotlin pour Android, vous pouvez définir les préférences


d'application en utilisant la classe SharedPreferences.
Voici un exemple de code pour créer et accéder aux préférences
d'application :
1. Créer un fichier de préférences xml: res/xml/[Link] :
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="[Link]
<PreferenceCategory android:title="Paramètres">
<CheckBoxPreference
android:key="notif_pref"
android:title="Activer les notifications"
android:defaultValue="true"/>
<ListPreference
android:key="lang_pref"
android:title="Langue"
android:entries="@array/langues"
android:entryValues="@array/langue_valeurs"
android:defaultValue="fr"/>
</PreferenceCategory>
</PreferenceScreen>
225
Préférences d’application
création et accès aux préférences

2. Dans votre activité, vous pouvez accéder aux préférences


d'application en créant une instance de SharedPreferences :

val prefs = [Link](this)

3. Vous pouvez maintenant accéder aux valeurs des préférences en


utilisant les clés que vous avez définies dans le fichier [Link] :

val notificationsActivées = [Link]("notif_pref", true)


val langue = [Link]("lang_pref", "fr")

Remarque: Vous pouvez également écouter les changements de


préférences en ajoutant un listener :

226
Préférences d’application
création et accès aux préférences

[Link] { sharedPreferences, key ->


when (key) {
"notif_pref" -> {
val notificationsActivées = [Link](key, true)
// Faire quelque chose avec la nouvelle valeur des notifications
}
"lang_pref" -> {
val langue = [Link](key, "fr")
// Faire quelque chose avec la nouvelle valeur de la langue
}
}
}

Cela vous permettra de détecter les changements de préférences


en temps réel et d'adapter votre application en conséquence.

227
Préférences d’application
Stockage des entiers, chaines et array

SharedPreferences est une interface de stockage de données


légère et facile à utiliser dans Android, qui vous permet de stocker
des données sous forme de clé-valeur. Vous pouvez stocker des
entiers, des chaînes et des tableaux dans SharedPreferences en
Kotlin de la manière suivante :

Pour stocker un entier :


val sharedPreferences = getSharedPreferences("MyPreferences", Context.MODE_PRIVATE)
val editor = [Link]()
[Link]("key", 123)
[Link]()

Dans cet exemple, nous utilisons la méthode putInt() pour stocker


l'entier 123 avec la clé "key" dans SharedPreferences. Nous devons
également utiliser la méthode apply() pour enregistrer les
changements. 228
Préférences d’application
Stockage des entiers, chaines et array

Pour stocker une chaine:


val sharedPreferences = getSharedPreferences("MyPreferences",
Context.MODE_PRIVATE)
val editor = [Link]()
[Link]("key", "valeur")
[Link]()

Ici, nous utilisons la méthode putString() pour stocker la chaîne


"valeur" avec la clé "key".

229
Préférences d’application
Stockage des entiers, chaines et array

Pour stocker un tableau:


val sharedPreferences = getSharedPreferences("MyPreferences",
Context.MODE_PRIVATE)
val editor = [Link]()
val tableau = arrayOf("valeur1", "valeur2", "valeur3")
[Link]("key", [Link]())
[Link]()

Nous utilisons la méthode putStringSet() pour stocker un


ensemble de chaînes avec la clé "key".
Pour convertir un tableau en ensemble, nous utilisons la méthode
toSet().

230
Préférences d’application
Récupérer des entiers, chaines et array

val nom_chaine = [Link]()("clé", "valeur par defaut")


val nom_int = [Link]()("clé", 0)
val nom_array = [Link]() ("clé",
emptySet()?.toTypedArray)

231
Il est temps de faire une
pause
C’est fini pour cette séance, rendez-vous la séance prochaine pour un
cours sur la programmation declarative avec Jetpack Compose

232
PROGRAMMATION
DECLARATIVE

AVEC JETPACK COMPOSE

233
SÉANCE 7-12

JETPACK
COMPOSE

234
Le cours de cette semaine porte sur Jetpack compose.
• Introduction à Jetpack Compose
• Installation, configuration et concepts de base de Jetpack Compose
• Layouts , contraintes et widgets
• Thèmes et styles
• Navigation et interactions
235
Introduction à Jetpack Compose
Présentation

❑ Jetpack Compose est une bibliothèque d'interface


utilisateur (UI) Android moderne et déclarative, développée
par Google. Elle permet de créer des interfaces utilisateur
dynamiques et personnalisées pour les applications Android,
en utilisant le langage de programmation Kotlin.
❑ Jetpack Compose utilise une approche déclarative pour
créer des interfaces utilisateur. Contrairement aux méthodes
traditionnelles basées sur le code XML, où vous devez définir
chaque élément de l'interface utilisateur séparément, Jetpack
Compose vous permet de définir l'interface utilisateur dans
une seule fonction, en utilisant des widgets réutilisables et
des fonctions pour modifier leur apparence.

236
Introduction à Jetpack Compose
Présentation

❑ Le code Jetpack Compose est plus simple, plus concis et plus


facile à comprendre que les méthodes traditionnelles basées
sur XML. Il est également plus facile de créer des interfaces
utilisateur dynamiques et personnalisées en utilisant Jetpack
Compose.

❑ Kotlin et Jetpack Compose sont des technologies très


prometteuses pour le développement Android, et les
développeurs Android devraient les apprendre pour rester
compétitifs et productifs.

237
Introduction à Jetpack Compose
Présentation

238
Introduction à Jetpack Compose
Présentation

239
Introduction à Jetpack Compose
Présentation

240
Introduction à Jetpack Compose
Applications créées avec Compose

241
Introduction à Jetpack Compose
Installation et configuration

Pour ajouter Jetpack Compose à un projet existant, suivez les


étapes suivantes :
1. Assurez-vous que vous utilisez Android Studio 4.0 ou une
version ultérieure.
2. Ouvrez le fichier [Link] de votre projet.
3. Ajoutez les dépendances suivantes à la section dependencies
du fichier [Link] :

dependencies {
// Jetpack Compose
implementation '[Link]:ui:1.1.0'
implementation '[Link]:material:1.1.0'
implementation '[Link]:runtime-livedata:1.1.0'
}

242
Introduction à Jetpack Compose
Installation et configuration

4. Ajoutez les plugins suivants à la section plugins du fichier


[Link] :

plugins {
id '[Link]' version '1.5.31'
id 'kotlin-parcelize'
id '[Link]'
id '[Link]-services'
id 'kotlin-android'
id 'kotlin-android-extensions'
}

243
Introduction à Jetpack Compose
Installation et configuration

5. Synchronisez le fichier [Link] en cliquant sur Sync Now.


Après avoir ajouté Jetpack Compose à votre projet, vous pouvez
commencer à utiliser les widgets et les fonctions de Jetpack
Compose pour créer des interfaces utilisateur modernes et
déclaratives.

Remarque: N'oubliez pas que Jetpack Compose est une


technologie relativement nouvelle et qu'il est important de
vérifier régulièrement les mises à jour pour vous assurer que
vous utilisez la dernière version et que vous bénéficiez des
dernières fonctionnalités et améliorations.

244
Introduction à Jetpack Compose
Création d’une application Android avec compose

245
Introduction à Jetpack Compose
Création d’une application Android avec compose

246
Introduction à Jetpack Compose
Création d’une application Android avec compose

247
Introduction à Jetpack Compose
Création d’une application Android avec compose

• La vue Projet (1) affiche les fichiers et les dossiers de votre projet.
• La vue Code (2) est la zone dans laquelle vous pouvez modifier le code.
• La vue Conception (3) vous permet d'afficher un aperçu de votre
application.
248
Introduction à Jetpack Compose
Présentation de la structure du code

Le code généré par défaut contient des fonctions générées


automatiquement, et en particulier onCreate() et setContent().

249
Introduction à Jetpack Compose
Présentation de la structure du code
❑ La fonction onCreate() est le point d'entrée de cette
application et elle appelle d'autres fonctions pour créer
l'interface utilisateur. Dans les programmes Kotlin, la
fonction main() est le point précis où démarre le compilateur
Kotlin dans votre code. Dans les applications Android, c'est
la fonction onCreate() qui remplit ce rôle.

❑ La fonction setContent() à l'intérieur de la fonction


onCreate() permet de définir votre mise en page au moyen
de fonctions modulables. Toutes les fonctions annotées avec
@Composable peuvent être appelées à partir de la
fonction setContent() ou d'autres fonctions modulables.
L'annotation indique au compilateur Kotlin que cette fonction
est utilisée par Jetpack Compose pour générer l'interface
utilisateur. 250
Introduction à Jetpack Compose
Présentation de la structure du code

❑ Examinez ensuite la fonction Greeting(). Elle est une


fonction modulable ; remarquez l'annotation @Composable
indiquée au-dessus. Une fonction modulable reçoit des
entrées et génère ce qui s'affiche à l'écran.

251
Introduction à Jetpack Compose
Présentation de la structure du code

IMPORTANT :

❑ La première lettre d'un nom de fonction @Composable est


mise en majuscule.
❑ L'annotation @Composable est ajoutée avant la fonction.
❑ Les fonctions @Composable ne peuvent rien renvoyer.

252
Introduction à Jetpack Compose
Présentation de la structure du code

❑ La fonction DefaultPreview() affiche un aperçu de la


fonction composable.
❑ En cliquant sur Compiler et actualiser. La compilation
peut prendre un certain temps. Une fois qu'elle est
terminée, l'aperçu affiche Hello Android! dans la zone de
texte.

❑ L'activité Compose vide contient tout le code nécessaire


pour créer cette application.
253
Introduction à Jetpack Compose
Présentation de la structure du code

❑ DefaultPreview() est une fonctionnalité particulièrement


utile qui vous permet de voir à quoi ressemble votre
application sans avoir à la compiler entièrement. Pour qu'il
s'agisse d'une fonction d'aperçu, vous devez ajouter une
annotation @Preview.
❑ Comme vous pouvez le constater, l'annotation @Preview
accepte un paramètre appelé showBackground. Si
showBackground est défini sur true, un arrière-plan est
ajouté à l'aperçu de votre application.
❑ Par défaut, Android Studio utilise un thème clair pour
l'éditeur. Il peut donc être difficile de voir la différence entre
showBackground = true et showBackground = false. Vous
pouvez toutefois voir la différence ci-dessous avec un thème
sombre. Notez que l'arrière-plan blanc de l'image est défini
sur "true". 254
Introduction à Jetpack Compose
Présentation de la structure du code

255
Etats de base de Jetpack Compose
Présentation des états de base

Jetpack Compose utilise des concepts de base pour créer


des interfaces utilisateur déclaratives. Voici quelques-uns
des concepts clés :
1. État (State) : L'état est une variable qui peut être
modifiée et qui détermine l'apparence et le comportement
d'un composant. Lorsque l'état est modifié, le composant
est redessiné automatiquement pour refléter le nouveau
état.
[Link] (Functions) : Les fonctions sont utilisées
pour décrire l'apparence et le comportement des
composants d'interface utilisateur. Elles prennent en entrée
des paramètres et renvoient un composant à afficher.

256
Etats de base de Jetpack Compose
Présentation des états de base

3. Compositions (Composables) : Les compositions sont des


fonctions qui utilisent d'autres fonctions pour décrire une partie de
l'interface utilisateur. Les compositions peuvent être imbriquées
pour créer des hiérarchies d'interface utilisateur plus complexes.
4. Widgets : Les widgets sont les composants de base utilisés
pour créer l'interface utilisateur. Ils peuvent être des boutons, des
champs de texte, des images, des listes, des tableaux, etc.
5. Modifier (Modifier) : Les modificateurs sont des fonctions qui
modifient l'apparence et le comportement des widgets. Ils peuvent
être utilisés pour définir des couleurs, des tailles, des polices, des
événements, etc.
En utilisant ces concepts de base, Jetpack Compose permet de
créer des interfaces utilisateur modernes et déclaratives, qui sont
plus faciles à comprendre et à modifier que les méthodes
traditionnelles basées sur le code XML. 257
Les Widgets de Jetpack Compose
Notion de mise en page

Les éléments de l'interface utilisateur sont organisés de façon


hiérarchique, avec des éléments contenus dans d'autres éléments.
Dans Compose, vous créez une hiérarchie d'interface utilisateur en
appelant des fonctions modulables à partir d'autres fonctions
modulables.
Dans Compose, les trois éléments de mise en page standards de
base sont :
1. Column :Cet élément de mise en page organise les widgets
verticalement les uns au-dessus des autres dans une colonne.
2. Row : Cet élément de mise en page organise les widgets
horizontalement côte à côte dans une ligne.
3. Box :Cet élément de mise en page organise les widgets les
uns au-dessus des autres en utilisant des coordonnées x et y

258
Les Widgets de Jetpack Compose
Notion de mise en page

259
Les Widgets de Jetpack Compose
Notion de mise en page
Column(
//modificateur
modifier=Modifier.
){
// les Widgets
}

Row(
//modificateur
){
// les Widgets
}

Box(
//modificateur
){
// les Widgets
260
}
Les Widgets de Jetpack Compose
Notion de mise en page
Les modificateurs sont utilisés pour ajouter des fonctionnalités ou
des comportements supplémentaires aux widgets et aux éléments
de mise en page. Les modificateurs sont chaînés à l'aide de
l'opérateur . , ce qui permet de les combiner pour créer des mises
en page plus complexes. Voici quelques exemples de modificateurs
couramment utilisés en Jetpack Compose :
• background: pour définir la couleur de fond d'un widget.
• border: pour ajouter une bordure à un widget.
• padding: pour ajouter un espace autour d'un widget.
• clickable: pour rendre un widget cliquable.
• fillMaxSize: pour remplir toute la taille disponible dans le
conteneur parent.
• align: pour aligner un widget à l'intérieur de son conteneur
parent.
• weight: pour définir la répartition de l'espace disponible entre
plusieurs widgets dans un conteneur. 261
Les Widgets de Jetpack Compose
Notion de mise en page

Row(
modifier = [Link](),
horizontalArrangement = [Link]
){

Column(
modifier = Modifier
.fillMaxSize()
.padding([Link])
.verticalScroll(rememberScrollState())
){

}
262
Les Widgets de Jetpack Compose
Présentation de Widgets

• Un widget est un composant d'interface utilisateur d'une


application.

• Dans le contexte de Jetpack Compose, un widget est un


composant d'interface utilisateur de base qui peut être utilisé
pour créer des interfaces utilisateur personnalisées.

• Les widgets de Jetpack Compose sont des éléments de


construction qui peuvent être combinés pour créer des
interfaces utilisateur complexes.

263
Les Widgets de Jetpack Compose
Présentation de Widgets

Text: utilisé pour afficher du texte. Il prend en charge diverses


propriétés de texte telles que la couleur, la taille, le style, etc.

Text (
text = "Je suis un texte",
style = TextStyle(
fontSize = [Link],
fontWeight = [Link],
color = [Link]
)
)

264
Les Widgets de Jetpack Compose
Présentation de Widgets

Image: utilisé pour afficher une image. Il prend en charge


diverses propriétés d'image telles que la forme, le
redimensionnement, etc.

Image(
painter = painterResource([Link].ic_launcher),
contentDescription = "My Image",
modifier = [Link]([Link])
)

265
Les Widgets de Jetpack Compose
Présentation de Widgets

Button : utilisé pour créer un bouton cliquable. Il prend en charge


diverses propriétés de bouton telles que la couleur, la forme, la
taille, etc.
Button(
onClick = { /* Do something */ },
modifier = Modifier
.padding([Link])
.fillMaxWidth(),
colors = [Link](
backgroundColor = [Link],
contentColor = [Link]
)
){
Text(text = "Button")
}
266
Les Widgets de Jetpack Compose
Présentation de Widgets

TextField: utilisé pour collecter du texte entré par l'utilisateur. Il


prend en charge diverses propriétés de champ de texte telles que
la couleur, la forme, la taille, etc

TextField(
value = "",
onValueChange = { /* Action à effectuer lors de la saisie de texte
*/ },
label = {
Text("Entrez votre texte ici")
},
modifier = [Link]()
)
267
Les Widgets de Jetpack Compose
Présentation de Widgets

Icon: est un widget de base de Jetpack Compose qui permet


d'afficher une icône à l'écran.

Icon(
[Link],
contentDescription = "Favorite Icon",
tint = [Link],
modifier = [Link]([Link])
)

268
Les Widgets de Jetpack Compose
Présentation de Widgets

IconButton: est un widget de base de Jetpack Compose qui


permet d'afficher une icône avec un bouton cliquable.
IconButton(
onClick = { /* Action à effectuer lors du clic sur l'icône */ },
modifier = [Link]([Link])
){
Icon(
[Link],
contentDescription = "Apple Icon",
tint = [Link],
modifier = [Link]([Link])
)
}

269
Les Widgets de Jetpack Compose
Présentation de Widgets

Chekbox: est un widget de base de Jetpack Compose qui permet


aux utilisateurs de sélectionner ou de désélectionner une option. Il
est souvent utilisé pour les choix binaires, tels que les cases à
cocher "Oui" ou "Non" ou les options "Activer" ou "Désactiver. Il
aussi utilisé pour collecter une valeur booléenne (vrai/faux) à
partir de l'utilisateur. Il prend en charge diverses propriétés de
case à cocher telles que la couleur, la forme, la taille, etc.
var isChecked by remember { mutableStateOf(false) }

Checkbox(
checked = isChecked,
onCheckedChange = { isChecked = it },
colors = [Link](
checkedColor = [Link],
uncheckedColor = [Link]
),
modifier = [Link]([Link])
) 270
Les Widgets de Jetpack Compose
Présentation de Widgets
RadioButton: utilisé pour collecter une valeur unique à partir d'une liste
d'options. Il prend en charge diverses propriétés de bouton radio telles
que la couleur, la forme, la taille, etc.
val options = listOf("Option 1", "Option 2", "Option 3")
var selectedOption by remember { mutableStateOf(options[0]) }

Column {
[Link] { option ->
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = [Link]),
verticalAlignment = [Link]
){
RadioButton(
selected = selectedOption == option,
onClick = { selectedOption = option },
modifier = [Link](horizontal = [Link])
)
Text(
text = option,
style = [Link].body1,
modifier = [Link](start = [Link])
)
}
} 271
}
Les Widgets de Jetpack Compose
Présentation de Widgets
Switch : utilisé pour collecter une valeur booléenne (vrai/faux) en
basculant entre deux états (activé et désactivé). Il prend en
charge diverses propriétés de commutateur telles que la couleur,
la forme, la taille, etc.
var switchState by remember { mutableStateOf(false) }
Column(
modifier = [Link]([Link])
){
Text(
text = "Activer la fonctionnalité",
style = [Link].subtitle1
)
Switch(
checked = switchState,
onCheckedChange = { switchState = it },
modifier = [Link](top = [Link]),
colors = [Link](
checkedThumbColor = [Link],
checkedTrackColor = [Link](alpha = 0.5f)
)
)
} 272
Les Widgets de Jetpack Compose
Présentation de Widgets
ProgressBar : utilisé pour afficher la progression d'une tâche. Il
prend en charge diverses propriétés de barre de progression telles
que la couleur, la forme, la taille, etc.
var progress by remember { mutableStateOf(0.5f) }

Column {
LinearProgressIndicator(
progress = progress,
modifier = [Link](),
color = [Link]
)
Spacer(modifier = [Link]([Link]))
Button(onClick = {
progress += 0.1f
if (progress >= 1f) progress = 0f
}) {
Text(text = "Increase progress")
}
} 273
Les Widgets de Jetpack Compose
Présentation de Widgets

Spacer : est un widget de base de Jetpack Compose qui est


utilisé pour ajouter de l'espace entre les éléments d'une interface
utilisateur. La taille de l'espace peut être définie à l'aide de
modificateurs

Spacer(modifier = [Link]([Link]))

274
Les Widgets de Jetpack Compose
Présentation de Widgets

Card : est un widget de Jetpack Compose qui vous permet


d'afficher du contenu dans une carte avec une ombre douce et un
fond arrondi. Il est souvent utilisé pour afficher des informations
sous forme de cartes.
Card(
modifier = Modifier
.fillMaxWidth()
.padding([Link]),
elevation = [Link]
){
Column(
modifier = [Link]([Link])
){
Text(
text = "Card Title",
style = [Link].h6
)
Spacer(modifier = [Link]([Link]))
Text(
text = "Card Content",
style = [Link].body1
)
}
} 275
Les Widgets de Jetpack Compose
Présentation de Widgets
LazyColumn : est un widget de Jetpack Compose qui permet d'afficher
une liste verticale de manière efficace. Contrairement à Column,
LazyColumn ne crée que les éléments qui sont actuellement visibles à
l'écran, ce qui permet de réduire l'utilisation de la mémoire et d'optimiser
les performances de l'application.
val names = listOf("Alice", "Bob", "Charlie", "David", "Emily", "Frank", "Grace", "Henry", "Ivy", "John")
val scrollState = rememberLazyListState()

LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding([Link]),
verticalArrangement = [Link]([Link]),
horizontalAlignment = [Link],
contentPadding = PaddingValues(vertical = [Link]),
reverseLayout = true,
state = scrollState,
){
items(names) { name ->
Text(
text = name,
modifier = [Link](),
textAlign = [Link],
style = [Link].h6
)
}
276
}
Les Widgets de Jetpack Compose
Présentation de Widgets
LazyRow : est un widget de Jetpack Compose qui permet d'afficher
une horizontale de manière efficace. Contrairement à Row, LazyRow ne
crée que les éléments qui sont actuellement visibles à l'écran, ce qui
permet de réduire l'utilisation de la mémoire et d'optimiser les
performances de l'application.
LazyRow(
modifier = [Link](),
horizontalArrangement = [Link]([Link])
){
items(10) { index ->
Box(
modifier = Modifier
.width([Link])
.height([Link])
.background([Link]),
contentAlignment = [Link]
){
Text(text = "Item $index", color = [Link])
}
}
277
}
Les Widgets de Jetpack Compose
Scaffold

❑ Scaffold est un widget de mise en page pratique qui


fournit une disposition de base pour les écrans courants
tels que les écrans d'accueil, les écrans de détails, les
formulaires, etc.
❑ Le widget Scaffold est construit sur le modèle de
conception "top-down" qui permet aux développeurs de se
concentrer sur la création des éléments de contenu plutôt
que sur la création des éléments de l'interface utilisateur
tels que les barres d'outils, les tiroirs de navigation, les
boutons d'action flottants, etc.
❑ Les éléments de Scaffold sont: topBar, bottomBar,
floatingActionButton et content (contenu de la page)

278
Les Widgets de Jetpack Compose
Scaffold

Scaffold(
topBar = {
//bar d’outils
},
bottomBar = {
//bar de navigation
},
floatingActionButton = {
//bouton flotante
},
content = {
//contenu de la page
}
) 279
Les Widgets de Jetpack Compose
topBar
Les éléments possibles de topBar sont:
❑ title : Le titre de la barre d'applications.
❑ subtitle : Le sous-titre de la barre d'applications.
❑ navigationIcon : L'icône de navigation à gauche de la barre
d'applications. On peut utiliser un IconButton avec une icône de
menu.
❑ actions : Les actions à droite de la barre d'applications. On peut
utiliser les IconButton avec des icônes de recherche, de favoris et de
partage. Etc..
❑ elevation : L'élévation de la barre d'applications, qui ajoute une
ombre pour donner une impression de profondeur.
❑ backgroundColor : La couleur de fond de la barre d'applications.
❑ contentColor : La couleur de texte des éléments de la barre
d'applications.
❑ navigationContentColor : La couleur de texte de l'icône de
navigation
280
Les Widgets de Jetpack Compose
topBar
topBar={TopAppBar(
title = { Text("My App") },
subtitle = { Text("Subtitle") },
navigationIcon = {
IconButton(onClick = { /* TODO */ }) {
Icon([Link])
}
},
actions = {
IconButton(onClick = { /* TODO */ }) {
Icon([Link])
}
IconButton(onClick = { /* TODO */ }) {
Icon([Link])
}
IconButton(onClick = { /* TODO */ }) {
Icon([Link])
}
},
elevation = [Link],
backgroundColor = [Link],
contentColor = [Link],
navigationContentColor = [Link],
modifier = [Link]([Link])
)
} 281
Les Widgets de Jetpack Compose
bottomBar

BottomNavigation peut contenir les éléments suivants :

• backgroundColor : La couleur de fond de la barre de


navigation inférieure.
• contentColor : La couleur de texte et d'icône des
éléments de la barre de navigation inférieure.
• elevation : L'élévation de la barre de navigation
inférieure, qui ajoute une ombre pour donner une
impression de profondeur.
• modifier : Définit la hauteur de la barre de navigation
inférieure.

282
Les Widgets de Jetpack Compose
bottomBar
BottomNavigation(
backgroundColor = [Link], // set the background color to blue
elevation = [Link] // set the elevation to 8dp
){
BottomNavigationItem(
selected = true,
onClick = { /* TODO */ },
icon = { Icon([Link], contentDescription = "Home") },
label = { Text("Home") },
selectedContentColor = [Link],
unselectedContentColor = [Link]
)
BottomNavigationItem(
selected = false,
onClick = { /* TODO */ },
icon = { Icon([Link], contentDescription = "Search") },
label = { Text("Search") },
selectedContentColor = [Link],
unselectedContentColor = [Link]
)
BottomNavigationItem(
selected = false,
onClick = { /* TODO */ },
icon = { Icon([Link], contentDescription = "Settings") },
label = { Text("Settings") },
selectedContentColor = [Link],
unselectedContentColor = [Link]
)

}
283
Les Widgets de Jetpack Compose
FloatingButton

• onClick : La fonction à exécuter lorsqu'on clique sur le


bouton.
• backgroundColor : La couleur de fond du bouton.
• contentColor : La couleur de l'icône et du texte sur le
bouton.
• content : Le contenu du bouton, qui peut être un texte,
une icône ou tout autre élément composé.
• elevation : L'élévation du bouton, qui ajoute une ombre
pour donner une impression de profondeur.
• modifier : Les modificateurs qui définissent la position et
la taille du bouton.

284
Les Widgets de Jetpack Compose
floatingActionButton

FloatingActionButton(
onClick = { /* action à exécuter lors du clic */ },
backgroundColor = [Link],
contentColor = [Link],
content = {
Icon([Link], contentDescription = "Ajouter")
},
elevation = [Link]([Link]),
modifier = [Link]([Link])
)

285
Exercice
Reproduire avec Jetpack compose les interfaces ci-dessous

286
Thèmes & styles

• Les thèmes et les styles sont des concepts clés dans le


développement Android, car ils permettent de
personnaliser l'apparence de l'interface utilisateur.
• Le thème d'une application est un ensemble de styles
prédéfinis pour différents éléments d'interface utilisateur,
tels que les boutons, les textes, les arrière-plans, etc. Les
thèmes sont souvent utilisés pour donner une apparence
cohérente à l'ensemble de l'application.
• Les styles sont des ensembles de propriétés qui
définissent l'apparence d'un élément spécifique
d'interface utilisateur, tel qu'un bouton ou un texte. Les
styles peuvent être définis de manière globale pour
l'ensemble de l'application ou de manière spécifique pour
un élément d'interface utilisateur individuel. 287
Thèmes & styles

• Jetpack Compose utilise également des thèmes et des


styles pour personnaliser l'apparence de l'interface
utilisateur. Cependant, la manière de définir les thèmes et
les styles est différente de celle des anciennes versions
d'Android, car Jetpack Compose utilise une approche plus
déclarative.
• Pour définir un thème dans Jetpack Compose, vous pouvez
utiliser la fonction MaterialTheme, qui définit un
ensemble de styles de matériaux. Vous pouvez également
définir vos propres styles personnalisés en utilisant la
fonction [Link] pour les
styles de texte, [Link] pour
les formes, et [Link] pour les
couleurs. 288
Thèmes & styles

Voici un exemple de définition d'un thème dans Jetpack


Compose :
val myTheme = darkColors(
primary = Color(0xFFBB86FC),
background = Color(0xFF121212)
)

@Composable
fun MyApp() {
MaterialTheme(colors = myTheme) {
// l'interface utilisateur de l'application
}
}
289
Thèmes & styles

• Pour définir un style personnalisé dans Jetpack Compose,


vous pouvez utiliser la fonction style et la propriété
Modifier pour appliquer le style à un élément d'interface
utilisateur spécifique.

Voici un exemple de définition d'un style pour un bouton :

290
Thèmes & styles

val TextStyle = [Link](


backgroundColor = Color(0xFFBB86FC),
contentColor = [Link],
)

Button(
onClick = { /* handle button click */ },
modifier = Modifier
.padding([Link])
.height([Link])
.width([Link]),
colors = TextStyle
){
Text("Cliquez ici")
}

} 291
Composition & recomposition

• La composition et la recomposition sont deux concepts


clés de Jetpack Compose.
• Jetpack Compose utilise une approche déclarative pour la
construction de l'interface utilisateur, ce qui signifie que
l'état de l'interface utilisateur est décrit dans une fonction
qui crée une représentation visuelle de l'interface
utilisateur en fonction de cet état.
• Cette fonction est appelée chaque fois que l'état change
et la représentation visuelle de l'interface utilisateur est
recomposée pour refléter les nouveaux états.
• Le processus de composition et de recomposition est
géré par le framework lui-même, il n'y a donc pas besoin
pour les développeurs de gérer manuellement ce
processus 292
Composition & recomposition

293
Composition & recomposition

294
La gestion des états
remember

La gestion de l'état est une partie importante de la création


d'interface utilisateur avec Jetpack Compose. Jetpack
Compose fournit plusieurs outils pour gérer l'état de
l'application, notamment :
1. mutableStateOf : c'est une fonction qui permet de
créer un état mutable, c'est-à-dire une variable qui peut
être modifiée et qui déclenche automatiquement une
recomposition de l'interface utilisateur lorsque sa valeur est
mise à jour. Voici un exemple :
var counter by remember { mutableStateOf(0) }

Button(onClick = { counter++ }) {
Text("Cliquez moi $counter fois")
}
295
La gestion des états
remember

2. remember : c'est une fonction qui permet de créer une


variable dont la valeur est mémorisée (ou "rappelée"),
c'est-à-dire qu'elle n'est pas recréée à chaque fois que la
composition est recomposée. Voici un exemple
val list = remember { mutableListOf<String>() }

[Link]("Nouvel élément")
Dans cet exemple, nous avons créé une liste list qui est
mémorisée à l'aide de la fonction remember. Nous avons
ensuite ajouté un nouvel élément à la liste. Chaque fois que
la composition est recomposée, list est rappelée avec les
mêmes éléments qu'auparavant, ce qui garantit la stabilité
de l'interface utilisateur. 296
La gestion des états
viewModel

3. viewModel : c'est une classe qui permet de stocker et


de gérer l'état de l'application de manière centralisée. Elle
est généralement utilisée pour stocker les données qui
doivent être partagées entre plusieurs composants de
l'interface utilisateur. Voici un exemple :
class MyViewModel : ViewModel() {
val counter = mutableStateOf(0)
}

@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
Button(onClick = { [Link]++ }) {
Text("Cliquez moi ${[Link]} fois")
}
}
297
Navigation avec Jetpack compose
Composant de navigation

• Navigation est une bibliothèque Jetpack qui permet de


naviguer d'une destination à une autre dans votre
application.

Pour utiliser cette bibliothèque de navigation Jetpack


compose, on il tout d’abord ajouter la dépendance en
procédant comme suit:
ouvrez le fichier de compilation de l'application, qui se
trouve ici : app/[Link]. Dans la section des
dépendances, ajoutez la dépendance navigation-compose.
implementation '[Link]:navigation-compose:2.5.3'

298
Navigation avec Jetpack compose
Composant de navigation

Voici les composants de navigation les plus couramment utilisés


en Jetpack Compose:
• NavHost - C'est le conteneur qui héberge les destinations de
navigation. Il est utilisé pour définir la zone dans laquelle la
navigation doit être effectuée.
• NavController - C'est un objet qui gère la navigation entre
les destinations. Il permet de naviguer vers une destination
en fonction de l'état actuel de l'application.
• NavGraph - C'est une représentation visuelle de la structure
de navigation de l'application. Il définit les différentes
destinations et les chemins de navigation qui les relient.
• NavDestination - C'est un élément de la hiérarchie de
navigation qui représente une destination à laquelle
l'utilisateur peut naviguer
299
Navigation avec Jetpack compose
Navigation entre écrans de compose

1. Ajouter la dépendance de navigation à votre projet


2. Ecrire les codes des différentes écrans de votre
application
3. Créer le graphe de navigation : vous pouvez créer les
fichiers suivants dans le package de navigation:
[Link] et [Link]

Ouvrez le fichier [Link] puis ajouter le code :


sealed class Screen(val route : String){
object Home :Screen("home_screen")
object Detail :Screen("detail_screen")
object Login:Screen("login_screen")
}

300
Navigation avec Jetpack compose
Navigation entre écrans de compose

Ouvrez le fichier [Link] puis ajoutez ce code:


@Composable
fun NavGraph (navController: NavHostController){
NavHost(
navController = navController,
startDestination = [Link])
{
composable(route = [Link]){
LoginScreen()
}
composable(route = [Link]){
HomeScreen()
}
composable(route = [Link]){
DetailScreen()
}
}
}

301
Navigation avec Jetpack compose
Navigation entre écrans de compose

4. Maintenant, allez dans notre [Link], ici vous


devez appeler votre NavGraph à l'intérieur de setContent /
NavigationTheme / Surface.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
[Link](savedInstanceState)
setContent {
NavigationTheme {
Surface(
modifier = [Link](),
color = [Link]
){

val navController = rememberNavController()


NavGraph(navController = navController)
}
}
}
}
} 302
Navigation avec Jetpack compose
Navigation entre écrans de compose

• Ici, nous devons créer le navController qui sera utilisé


dans l'application.

• Tout d'abord, nous créons une nouvelle variable


navController en appelant rememberNavController().

• Cette fonction remember retourne toujours le même


objet et nous permet de ne pas perdre cet objet si nous
apportons des modifications de configuration, telles que
changer l'orientation de l'écran.

303
Navigation avec Jetpack compose
Navigation entre écrans de compose

5. Jusqu'à présent, tout va bien... Maintenant, nous devons


ajouter la navigation aux boutons, pour passer d'un écran à
un autre.

Allez dans le fichier [Link], puis ajouter le


paramètre navController à tous les écrans qui utiliserons
la navigation. Par exemple on peut ajouter à LoginScreen
et HomeScreen, pour leur permettre d'utiliser le NavGraph
lorsque nous cliquons sur le bouton.

Le code du fichier [Link] devient donc :

304
Navigation avec Jetpack compose
Navigation entre écrans de compose

@Composable
fun NavGraph (navController: NavHostController){
NavHost(
navController = navController,
startDestination = [Link])
{
composable(route = [Link]){
LoginScreen(navController)
}
composable(route = [Link]){
HomeScreen(navController)
}
composable(route = [Link]){
DetailScreen()
}
}
} 305
Navigation avec Jetpack compose
Navigation entre écrans de compose

Ensuite, ouvrez les fichiers [Link] et


[Link] et ajoutez le navController en tant que
paramètre pour les deux.

@Composable
fun LoginScreen(navController: NavController)

@Composable
fun HomeScreen(navController: NavController)

306
Navigation avec Jetpack compose
Navigation entre écrans de compose

6. Maintenant, à l'intérieur des codes sources de vos


écrans, vous pouvez appelez le navigation vers un autre
écran à l'intérieur de l'événement onClick du bouton , d’un
texte, ou d’un autre widget:

onClick = {
//TODO: Navigate to Home Screen
[Link]([Link])
}

307
Navigation avec Jetpack compose
Passage d’arguments lors de la navigation

[Link] votre écran source, vous pouvez passer la valeur de


"name" à l'aide de la méthode navigate() du NavController :

composable(
"destination/{name}",
arguments = listOf(navArgument("name") { type =
[Link] })
) { backStackEntry ->
DestinationScreen(
name = [Link]?.getString("name")
)
}

308
Navigation avec Jetpack compose
Passage d’arguments lors de la navigation

[Link] envoyer des données à un écran lors de la navigation,


vous pouvez utiliser les arguments de navigation.

Button(
onClick = {
[Link]("destination/Jean")
}
){
Text("Aller à la destination avec le nom Jean")
}

309
Navigation avec Jetpack compose
Passage d’arguments lors de la navigation

3. Dans votre écran de destination, vous pouvez récupérer la


valeur de "name" en utilisant le constructeur de la destination

@Composable
fun DestinationScreen(name: String?) {
// Utilisez la valeur de "name" ici
}

310
XML & Jetpack compose
Interopérabilité entre XML et Jetpack compose

311
XML & Jetpack compose
Interopérabilité entre XML et Jetpack compose

Jetpack Compose et XML peuvent coexister dans une même


application Android. Les développeurs peuvent utiliser
Jetpack Compose pour créer des parties de l'interface
utilisateur, tout en utilisant XML pour d'autres parties de
l'interface utilisateur.

L'interopérabilité entre Jetpack Compose et XML est possible


grâce à l'utilisation de View composables. Les View
composables permettent d'intégrer des éléments de
l'interface utilisateur basés sur XML dans une interface
utilisateur Jetpack Compose.

312
XML & Jetpack compose
ComposeView

ComposeView est une vue Android qui permet d'afficher et


de gérer le contenu Jetpack Compose dans une application
Android. Il s'agit d'un élément d'interface utilisateur
personnalisé qui peut être ajouté à une mise en page XML ou
créé dynamiquement dans le code.

L'utilisation de ComposeView permet d'intégrer


progressivement Jetpack Compose dans une application
Android existante, en permettant de créer des parties de
l'interface utilisateur à l'aide de Jetpack Compose tout en
conservant le reste de l'application en XML.

313
XML & Jetpack compose
ComposeView

ComposeView est une vue Android qui permet d'afficher et


de gérer le contenu Jetpack Compose dans une application
Android. Il s'agit d'un élément d'interface utilisateur
personnalisé qui peut être ajouté à une mise en page XML ou
créé dynamiquement dans le code.

L'utilisation de ComposeView permet d'intégrer


progressivement Jetpack Compose dans une application
Android existante, en permettant de créer des parties de
l'interface utilisateur à l'aide de Jetpack Compose tout en
conservant le reste de l'application en XML.

314
XML & Jetpack compose
ComposeView

Voici les étapes à suivre pour installer ComposeView et


Jetpack Compose :
1. Ouvrez le fichier [Link] de votre module
d'application.
2. Ajoutez la dépendance à Jetpack Compose dans la section
des dépendances :

dependencies {
implementation '[Link]:ui:1.1.0'
implementation '[Link]:material:1.1.0'
implementation '[Link]:runtime-livedata:1.1.0'
}

315
XML & Jetpack compose
ComposeView

3. Assurez-vous que la version de [Link],


[Link] et [Link]-livedata
correspond à la version de Jetpack Compose que vous
souhaitez utiliser.
4. Synchronisez votre projet avec Gradle pour télécharger les
dépendances.
5. Après avoir installé Jetpack Compose, vous pouvez utiliser
ComposeView dans votre code en important la classe
[Link]. Vous pouvez
ensuite créer une instance de ComposeView dans votre code
et lui attribuer une fonction Composable pour afficher le
contenu Jetpack Compose.

316
XML & Jetpack compose
ComposeView

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


<LinearLayout
xmlns:android="[Link]
xmlns:app="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<[Link]
android:id="@+id/myComposeView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>

</LinearLayout>
317
XML & Jetpack compose
ComposeView

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)

// inflate the XML layout


setContentView([Link].activity_main)

// reference the ComposeView using findViewById


val composeView = findViewById<ComposeView>([Link])

// set up the Composable function for the ComposeView


[Link] {
// define the user interface using Jetpack Compose
}
}
} 318
SÉANCE 13

SQLITE

319
Le cours de cette semaine porte sur les bases de données SQLite .
• Création d'une base de données SQLite
• Requêtes SQL en Kotlin

320
Introduction à SQLite
Présentation de SQLite

❑ SQLite est un système de gestion de base de données


relationnelle open-source qui a été développé par Richard
Hipp en 2000.
❑ Il est intégré dans la plupart des systèmes d'exploitation, y
compris Android, iOS et Windows, et est largement utilisé
pour stocker des données dans les applications mobiles, les
navigateurs web, les systèmes de gestion de contenu, etc.
❑ SQLite est un système de gestion de base de données
relationnelle léger qui ne nécessite pas de configuration de
serveur.
❑ Les données sont stockées dans un seul fichier de base de
données qui peut être transféré facilement d'un emplacement
à un autre.

321
Introduction à SQLite
Présentation de SQLite

❑ Il est également rapide et efficace, avec des performances


comparables à celles d'autres systèmes de gestion de base de
données relationnelle tels que MySQL et PostgreSQL.

❑ En plus d'être léger et rapide, SQLite offre une gamme de


fonctionnalités telles que la prise en charge de transactions
ACID (Atomicité, Cohérence, Isolation, Durabilité), la gestion
des contraintes de clé primaire et étrangère, et la prise en
charge de nombreuses fonctions SQL courantes.

❑ Il est également compatible avec de nombreux langages de


programmation, y compris Kotlin, Java, C et Python.

322
Introduction à SQLite
Kotlin et SQLite

Kotlin simplifie la gestion de la base de données SQLite en


offrant des fonctionnalités spécifiques qui facilitent la gestion
des données, réduisent le code nécessaire pour effectuer des
opérations sur la base de données et améliorent la sécurité du
code.
Voici quelques exemples de la façon dont Kotlin simplifie la
gestion de la base de données SQLite :
• Sécurité de type et nullabilité: Kotlin offre une sécurité de
type qui permet aux développeurs de détecter les erreurs de
type à la compilation plutôt qu'à l'exécution. Cela aide à
prévenir les erreurs courantes telles que les exceptions de
pointeur null (NullPointerException) et les erreurs de type lors
de la manipulation de données dans la base de données
SQLite.
323
Introduction à SQLite
Kotlin et SQLite

• Fonctions d'extension : Kotlin permet aux développeurs


d'ajouter des fonctions d'extension à des classes existantes.
Cela permet de simplifier le code et d'améliorer la lisibilité en
encapsulant des fonctionnalités courantes dans des fonctions
réutilisables qui peuvent être utilisées à plusieurs endroits
dans le code.
• Fonctions lambda : Kotlin prend en charge les fonctions
lambda, ce qui facilite la création de requêtes SQL complexes.
Les fonctions lambda permettent aux développeurs d'écrire
des requêtes SQL de manière plus concise et de les rendre
plus faciles à lire et à comprendre.

324
Introduction à SQLite
Kotlin et SQLite

• Prise en charge de l'interopérabilité : Kotlin est conçu


pour être compatible avec Java et peut facilement interagir
avec du code Java existant. Cela facilite l'utilisation de
bibliothèques et d'outils existants pour la gestion de la base
de données SQLite dans Kotlin.

325
Base de données SQLite
Création de BD et de ses tables

Pour créer une base de données SQLite avec Kotlin dans une
application Android, vous devez suivre les étapes suivantes :

1. Importez la bibliothèque SQLite dans votre projet Kotlin.


Vous pouvez le faire en ajoutant la dépendance suivante
dans votre fichier [Link] :

2. Créez une classe de gestionnaire de base de données qui


étend SQLiteOpenHelper. Cette classe gérera la création de
la base de données et la mise à niveau de la base de
données au fil du temps. Voici un exemple de code :
326
Base de données SQLite
Création de BD et de ses tables

class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null,


DATABASE_VERSION) {
override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL(CREATE_TABLE)
}

override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {


db?.execSQL("DROP TABLE IF EXISTS $TABLE_NAME")
onCreate(db)
}
companion object {
private const val DATABASE_VERSION = 1
private const val DATABASE_NAME = "my_database"
private const val TABLE_NAME = "my_table"
private const val COLUMN_ID = "id"
private const val COLUMN_NAME = "name"
private const val CREATE_TABLE = "CREATE TABLE $TABLE_NAME ($COLUMN_ID INTEGER
PRIMARY KEY AUTOINCREMENT, $COLUMN_NAME TEXT)"
}
} 327
Base de données SQLite
Création de BD et de ses tables

3. Utilisez la classe de gestionnaire de base de données pour


créer une instance de base de données dans votre code Kotlin.
Vous pouvez le faire en utilisant le code suivant :
val dbHelper = DatabaseHelper(this)
val db = [Link]

4. Utilisez la méthode execSQL pour exécuter une requête SQL


pour créer une table dans la base de données :
val createTableQuery = "CREATE TABLE my_table (id INTEGER PRIMARY KEY
AUTOINCREMENT, name TEXT)"
[Link](createTableQuery)

328
Base de données SQLite
Clé primaire et clé étrangère

Pour ajouter une contrainte de clé primaire à une colonne, vous


pouvez ajouter l'attribut PRIMARY KEY à la définition de la
colonne lors de la création de la table. Par exemple, pour
ajouter une clé primaire à la colonne "id" de la table "users" :

override fun onCreate(db: SQLiteDatabase?) {


db?.execSQL("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT,
email TEXT)")
}

329
Base de données SQLite
Clé primaire et clé étrangère

Pour ajouter une contrainte de clé étrangère à une colonne,


vous pouvez ajouter l'attribut FOREIGN KEY à la définition de la
colonne lors de la création de la table. Par exemple, pour
ajouter une clé étrangère à la colonne "user_id" de la table
"posts" :

override fun onCreate(db: SQLiteDatabase?) {


db?.execSQL("CREATE TABLE posts (id INTEGER PRIMARY KEY, title TEXT, content TEXT,
user_id INTEGER, FOREIGN KEY(user_id) REFERENCES users(id))")
}

330
Base de données SQLite
Manipulation des données

La manipulation des données dans SQLite concerne les


opérations suivantes:

- l’ajout des enregistrements


- La mise à jour des données
- La sélection ou l’affichage des données
- La suppression des données

331
Base de données SQLite
Ajouter les enregistrements

Pour insérer des données dans une table vous pouvez utiliser la
méthode insert de la classe SQLiteDatabase.
Voici un exemple de code pour insérer un nouvel utilisateur avec
un nom et une adresse e-mail :
val dbHelper = DatabaseHelper(this)
val db = [Link]

val values = ContentValues().apply {


put("name", [Link]())
put("email", [Link]())
}
val newRowId = [Link]("users", null, values)

if (newRowId == -1L) {
// L'insertion a échoué
[Link](this,"Erreur lors de l'insertion!",Toast.LENGTH_SHORT).show()
} else {
// L'insertion a réussi
[Link](this,"Insertion réussie avec l'ID $newRowId",Toast.LENGTH_SHORT).show()
}
332
Base de données SQLite
Affichage des données

Pour afficher les données stockées dans une base de données


SQLite avec Kotlin, vous pouvez utiliser une requête SQL
SELECT pour récupérer les données souhaitées. Vous pouvez
ensuite parcourir le curseur résultant et afficher les données.

Voici un exemple de code qui montre comment afficher toutes


les données de la table "users" dans une ListView :

333
Base de données SQLite
Affichage des données

val dbHelper = DatabaseHelper(this)


val db = [Link]

val cursor = [Link]("SELECT * FROM users", null)

val userList = ArrayList<String>()


if ([Link]()) {
do {
val name = [Link]([Link]("name"))
val email = [Link]([Link]("email"))
val userInfo = "Nom : $name | email : $email "
[Link](userInfo)
} while ([Link]())
}

val listView = findViewById<ListView>([Link])


val adapter = ArrayAdapter(this, [Link].simple_list_item_1, userList)
[Link] = adapter
334
Base de données SQLite
Affichage des données

• Dans cet exemple, nous récupérons toutes les données de la table


"users" à l'aide de la méthode rawQuery, qui prend une requête
SQL en paramètre et renvoie un curseur contenant les résultats.
• Nous parcourons ensuite le curseur à l'aide d'une boucle while et
récupérons les valeurs de chaque colonne à l'aide des méthodes
getString du curseur.
• Nous stockons ensuite les informations de chaque utilisateur dans
une chaîne de caractères et les ajoutons à une liste d'utilisateurs.
• Enfin, nous utilisons un ArrayAdapter pour afficher la liste
d'utilisateurs dans une ListView.
• Notez que dans cet exemple, nous avons utilisé une méthode
readableDatabase pour obtenir une référence à la base de
données. Si vous avez besoin de modifier les données de la base de
données, vous devrez utiliser la méthode writableDatabase à la
place.
335
Base de données SQLite
Mises à jour des données

Pour mettre à jour des données existantes dans une table, vous
pouvez utiliser la méthode update de la classe SQLiteDatabase.
Voici un exemple de code pour mettre à jour l'adresse e-mail de
l'utilisateur ayant un ID spécifique :

val values = ContentValues().apply {


put("email", "newemail@[Link]")
}
val selection = "id = ?"
val selectionArgs = arrayOf("1")
val count = [Link]("users", values, selection, selectionArgs)

336
Base de données SQLite
Suppression des données

Pour supprimer des données de la table "users", vous pouvez


utiliser la méthode delete de la classe SQLiteDatabase. Voici un
exemple de code pour supprimer un utilisateur ayant un ID
spécifique :

val selection = "id = ?"


val selectionArgs = arrayOf("1")
val deletedRows = [Link]("users", selection, selectionArgs)

337
Base de données SQLite
Exercice

Exercice :
Créer une application Android qui permettant de gérer les
utilisateurs d’un site internet.
L’application doit permettre d’enregistré, de modifier de
supprimer et de mettre à jour les informations sur les
utilisateurs.
Un utilisateur dispose d’un identifiant, d’un nom , d’un mot
de passe, d’un adresse e-mail, d’un numéro de telephone et
d’une adresse.

338
Base de données SQLite
Exercice

339
Base de données SQLite
Exercice

340
Base de données SQLite
La jointure

Une jointure (ou "join" en anglais) est une opération SQL


permettant de combiner les données de deux ou plusieurs
tables en une seule.

En général, une jointure est effectuée en spécifiant une ou


plusieurs colonnes communes entre les tables, qui sont
utilisées pour associer les lignes des tables.

Pour effectuer une jointure SQLite en Kotlin, vous pouvez


utiliser la méthode rawQuery() du SQLiteDatabase

341
Base de données SQLite
La jointure

Exemple:
Supposons que nous avons deux tables : users et orders.
La table users contient des informations sur les utilisateurs,
notamment leur nom et leur adresse électronique, et la table
orders contient des informations sur les commandes passées
par ces utilisateurs, notamment la date de commande et le
montant total de la commande. Les deux tables sont liées
par l'identifiant de l'utilisateur, qui est une clé étrangère
dans la table orders.

Nous voulons obtenir les informations sur les commandes et


les utilisateurs associées

342
Base de données SQLite
La jointure
val dbHelper = DatabaseHelper(this)
val db = [Link]
val projection = arrayOf("[Link]", "[Link]")
val selection = "[Link] = orders.user_id"
val sortOrder = "[Link] DESC"
val cursor = [Link](
"users INNER JOIN orders ON [Link] = orders.user_id", // Tables et jointure
projection, // Colonnes à retourner
selection, // Clause WHERE
null, // Arguments de la clause WHERE
null, // GROUP BY
null, // HAVING
sortOrder // Clause ORDER BY
)
val userList = ArrayList<String>()
if ([Link]()) {
do {
val name = [Link]([Link]("name"))
val product = [Link]([Link]("product"))
val userInfo = "Nom : $name | Produit : $product"
[Link](userInfo)
} while ([Link]())
} 343
Base de données SQLite
La jointure

Dans cet exemple, nous utilisons la méthode query() pour


effectuer une jointure entre les tables users et orders en
utilisant une clause INNER JOIN avec la condition [Link]
= orders.user_id. Nous spécifions également les colonnes
à retourner (projection), la clause WHERE (selection) et la
clause ORDER BY (sortOrder).

344
Base de données SQLite
Exercice

Exercice pratique: 1/3


Supposons que vous développez une application Android pour une
entreprise qui vend des produits électroniques. L'application
permettra aux clients de parcourir les produits disponibles, de les
ajouter à leur panier et de passer des commandes. Vous êtes
chargé de créer la base de données SQLite pour cette application.
Voici les informations que vous devez stocker pour chaque table :
• La table "Produits" doit stocker les informations suivantes pour
chaque produit : l'identifiant du produit (entier), le nom du
produit (chaîne), la description du produit (chaîne), le prix
unitaire du produit (décimal), la quantité disponible en stock
(entier).
345
Base de données SQLite
Exercice

Exercice pratique : 2/3


• La table "Clients" doit stocker les informations suivantes pour chaque
client : l'identifiant du client (entier), le nom du client (chaîne),
l'adresse e-mail du client (chaîne), le numéro de téléphone du client
(chaîne).
• La table "Commandes" doit stocker les informations suivantes pour
chaque commande : l'identifiant de la commande (entier), la date de
la commande (date/heure), l'identifiant du client qui a passé la
commande (entier), l'état de la commande (en attente, expédiée,
livrée, annulée).
• La table "CommandeProduits" doit stocker les informations suivantes
pour chaque produit inclus dans une commande : l'identifiant de la
commande (entier), l'identifiant du produit (entier), la quantité
commandée (entier). 346
Base de données SQLite
Exercice

Exercice pratique : 3/3

En utilisant Kotlin pour Android, écrivez le code nécessaire pour créer


la base de données SQLite avec ces tables et leurs relations. Assurez-
vous d'utiliser les contraintes de clé primaire et étrangère pour
garantir l'intégrité des données.

347
Et C’est tout !

C’est fini avec ce cours


Rendez vous sur :

[Link]

[Link]

Pour plus des contenus sur jetpack compose

348

Common questions

Alimenté par l’IA

Jetpack Compose offers a declarative approach to building Android UIs, allowing developers to create complex interfaces using composable functions with Kotlin code. This reduces boilerplate code, enhances UI management, and allows real-time UI updates. Interoperability with XML allows existing XML layouts to integrate smoothly, enabling gradual adoption of Compose in legacy projects. It simplifies managing state and event handling through its built-in modifiers and live updates .

Android ListView uses adapters, like ArrayAdapter, to bridge the data set and the ListView, efficiently managing data presentation. ListView leverages View recycling and reuses item views, minimizing memory use by only maintaining visible views and a limited number of off-screen views. This optimization reduces the need for constantly inflating and destroying views, ensuring smoother scrolling and improved overall performance .

RecyclerView enhances ListView by offering more flexible layouts through LayoutManager, supporting horizontal and grid layouts natively, unlike the linear layout of ListView. It uses a ViewHolder pattern to improve performance by caching view references, significantly reducing view inflation overhead. RecyclerView's modular adapter pattern and efficient onChangeListeners allow seamless large data set management without impacting performance, making it an efficient choice for complex UIs .

To create a string array resource in an Android application, you define it in the res/values/arrays.xml file using the <string-array> tag. You can then access this resource in your Kotlin code using the resources.getStringArray(R.array.resource_name) method, which returns an Array<String> .

Resource identifiers in Android are defined using the @+id/ notation within layout XML files to create new IDs. Once defined, these IDs can be used to reference the corresponding views through R.id.id_name in Kotlin code. This system enables developers to programmatically access and manipulate UI elements efficiently, ensuring consistent and organized code management .

Vector drawables provide resolution-independent images, ensuring crisp visuals at any screen size or density, directly benefiting app performance by reducing the number and size of drawable files needed for different resolutions. Unlike PNGs, they scale without quality loss, significantly cutting down on drawable resource variants and decreasing APK size. However, complex vector graphics might incur more processing than static PNGs, affecting performance when used excessively .

LiveData in Jetpack Compose facilitates efficient state management by providing observable data holders that notify composables of data changes, ensuring UIs reflect the latest data without manual updates. You declare LiveData within ViewModel and observe it within composable functions using observeAsState(), enabling automatic UI recomposition on data change, enhancing response to dynamic data .

Integrating Jetpack Compose with XML-based projects allows for leveraging Compose's declarative UI benefits, such as reduced boilerplate and state handling, while maintaining the familiarity and stability of existing XML layouts. This hybrid approach facilitates gradual migration, reducing the overhead of complete redesigns. Limitations might include increased complexity in managing two paradigms and potential discrepancies in behavior across UI systems. ComposeView bridges this gap, allowing Composable functions within XML layouts .

The Android layout management system uses various ViewGroup subclasses to organize UI components efficiently. LinearLayout can align components in a row or column, while RelativeLayout and ConstraintLayout position components in relation to each other. TableLayout organizes components into rows and columns like a table. These layouts form a view tree structure, enabling a clear hierarchical representation of UI components .

The @Composable annotation in Jetpack Compose marks a Kotlin function as capable of generating UI components declaratively. It instructs the Compose compiler to manage and track the state of the UI elements it creates. The function can be called from setContent() or other @Composable functions, allowing a modular and reusable component-based architecture for UI design .

Vous aimerez peut-être aussi