Le niveau sonore
Aujourd’hui, on va encore développer notre interface utilisateur avec l’intégration des contrôles du volume. C’est la dernière ligne droite avant de commencer à implémenter le cœur de notre lecteur musical, alors accroche-toi !
Tout l’art de reproduire
Allez, reprenons donc la maquette, voici ce que l’on devra reproduire dans l’app :
Comme tu peux le constater, ce n’est rien d’autre qu’un bouton pour couper le son et une barre de contrôle du volume sonore. Ça ne devrait pas être très long, commence par télécharger les différentes images utilisées pour afficher l’état du volume.
Volume_Tracker_-_Images.zipEn décompressant ce fichier, tu verras 4 nouvelles images:
Ici, on a donc une image pour chaque niveau de volume : quand il est très fort, moyen ou très bas. D’ailleurs, il y en a même une pour quand le son sera coupé.
Maintenant que tu as les images, il ne te reste alors plus qu’à les inclure dans le dossier Resources/Images, exactement comme la dernière fois !
À vos marques, prêt ? Codez !
C’est bon, tout est prêt ? Allez on passe au code !
Pour cela, on aura besoin d’un ImageButton pour couper le son et d’un Slider pour contrôler le volume sonore de manière précise.
Eh oui ! Techniquement, c’est du déjà-vu, alors essaye de reproduire ces contrôles par toi-même avant de regarder le code qui suit :
Nom du fichier :MusicPlayerView.cs
|
|
Voilà, on a donc défini un ImageButton avec une image par défaut, et un Slider pour contrôler le volume sonore de 0% à 100%. Et tu l’auras sûrement noté, le Slider est composé d’une barre noire qui représente le volume actuel, et d’une barre grise pour le volume supérieur disponible.
Il ne te reste alors plus qu’à rajouter les contrôles dans le BottomLayout :
Nom du fichier :MusicPlayerView.cs
|
|
Alors, tu avais bien pensé à appliquer un ColumnSpan ? 😛 On en a en effet besoin pour afficher la barre de son à cheval sur trois colonnes de notre Grid.
Allez, il est temps de relancer l’appli ! Voyons ce que ça donne :
Bon, cette fois-ci, il n’y avait que deux composants à définir, alors on va aller un petit plus loin. Tu te rappelles des différentes images pour notre volume ? Il est temps de leur trouver une utilité !
L’idée, c’est que notre MuteButton
change d’apparence en fonction du niveau de volume demandé. On aura donc une référence directe au VolumeTracker
pour trouver la bonne image à associer au MuteButton
. Pour cela, on utilisera un DataTrigger qui permet de modifier la propriété d’un objet lorsqu’une certaine valeur est détectée.
Prenons le cas le plus simple, celui où le volume sonore détecté est de 0 :
Nom du fichier :MusicPlayerView.cs
|
|
Dans un premier temps, on précise sur quel type d’objet appliquer des modifications. Dans notre cas, ce sera un ImageButton, puisque c’est l’image du MuteButton
que l’on veut changer :
Nom du fichier :MusicPlayerView.cs
|
|
Puis, à l’aide d’un Setter, on demande au VolumeOffTrigger
de changer la source d’image du MuteButton
pour l’icône correspondant au volume éteint :
Nom du fichier :MusicPlayerView.cs
|
|
Or, la modification ne doit s’appliquer que dans le cas où la valeur du VolumeTracker
atteint 0 !
Ceci est rendu possible par la technique du Binding. On crée alors un lien vers ce composant pour suivre l’évolution de la propriété Value :
Nom du fichier :MusicPlayerView.cs
|
|
Enfin, la valeur cible à atteindre est définie dans le VolumeOffTrigger
de cette façon :
Nom du fichier :MusicPlayerView.cs
|
|
En résumé, on a donc un déclencheur qui modifiera l’icône au moment où l’utilisateur abaissera la valeur du Slider à zéro.
Héhé, bien vu ! En effet, ce n’était pas une erreur typographique 😄
En fait, la documentation du Slider précise que la propriété Value est de type double. Cela donne à l’utilisateur un peu plus de contrôle quand il manipule un Slider (à la virgule près !).
Or, si tu supprimes le “d” et que tu passes ta souris au-dessus du “0”, tu constateras que ce n’est plus considéré comme un double, mais un int !
Et comme la propriété Value de notre déclencheur est de type object, elle accepte potentiellement n’importe quel type de valeur. On doit donc explicitement lui indiquer comment considérer ce “0” : comme un double !
On doit rajouter le “d” juste après :
Il ne reste alors plus qu’à rattacher ce déclencheur à notre composant MuteButton
. D’ailleurs, comme il sera sujet à des configurations supplémentaires, on va isoler son initialisation dans une méthode InitMuteButton()
. Cela permettra de garder notre code clair :
Nom du fichier :MusicPlayerView.cs
|
|
Et voilà ! Essaye maintenant de glisser la valeur du Slider tout à gauche :
Un bouton dans tous ses états !
Maintenant que tu sais comment fonctionnent les déclencheurs, on va en créer d’autres pour gérer tous les différents états du bouton.
Fonctionnellement, voici ce que l’on aimerait mettre en place :
l’icône du volume bas apparaîtra pour toutes les valeurs comprises entre 1 et 15,
entre 16 et 50, on affichera l’icône du volume modéré,
et pour l’icône du volume élevé, ce sera entre 51 et 100.
Pour tous ces cas-là, le déclencheur ne dépend plus d’une seule valeur bien précise, mais plutôt de toute une plage de valeurs. On va donc faire appel à un nouveau déclencheur spécifique, le MultiTrigger. C’est le même principe que pour le DataTrigger, à la différence que le MultiTrigger dépendra du résultat de plusieurs conditions. Je vais t’expliquer juste après.
Pour le moment, déclarons nos trois nouveaux états possibles :
Nom du fichier :MusicPlayerView.cs
|
|
Tout ce qu’on a fait, c’est définir les changements d’apparence à l’aide de Setters, pour un volume bas, moyen ou élevé.
On peut désormais définir les conditions de déclenchement pour ces trois états. Modifie la méthode InitMuteButton()
comme indiqué ci-après :
Nom du fichier :MusicPlayerView.cs
|
|
Oui je sais, ça peut faire beaucoup d’un coup, mais ce n’est pas dur à comprendre. D’ailleurs, tu peux voir qu’on répète souvent les mêmes opérations dans ce bout de code !
A ce stade, quelques erreurs auront probablement été mises en évidence par Visual Studio. Pour les résoudre, déclare les en-têtes suivantes tout en haut du fichier :
Nom du fichier :MusicPlayerView.cs
|
|
Il est maintenant temps de passer aux explications. Décortiquons un peu cette méthode InitMuteButton()
en commençant par cette portion de code :
Nom du fichier :MusicPlayerView.cs
|
|
Ça paraît déjà plus simple comme ça, non ? Tout ce qu’on fait ici, c’est ajouter à chacun des déclencheurs deux conditions nécessaires au changement d’icône du MuteButton
.
Par exemple, si tu regardes pour le VolumeLowTrigger
, tu verras que la première condition de déclenchement est liée à une valeur minimale de 1, tandis que l’autre condition dépend d’une valeur maximale de 15. Ça te rappelle quelque chose maintenant ?
Tout à fait ! Et la même logique s’applique pour le VolumeMediumTrigger
et le VolumeHighTrigger
. 🙂
Bon, mais ça n’est pas magique non plus ! La création de ces conditions s’appuie sur les méthodes CreateMinRangeCondition(double value)
et CreateMaxRangeCondition(double value)
:
Nom du fichier :MusicPlayerView.cs
|
|
La première méthode représente la valeur minimale de déclenchement du nouvel état, et la seconde la valeur maximale. Pour créer ces conditions, il faut donc une valeur cible, et un type d’opérateur : GreaterOrEqual
ou SmallerOrEqual
.
Ces paramètres sont justement pris en compte par une méthode de base définie tout au début du InitMuteButton()
. Elle reprend le même principe que pour le DataTrigger qui est utilisé pour le déclencheur VolumeOffTrigger
:
Nom du fichier :MusicPlayerView.cs
|
|
La seule nouveauté ici, c’est qu’on ne cherche plus à atteindre une valeur cible numérique (comme auparavant avec le “0”). En effet, on se base plutôt sur le résultat d’une comparaison.
Le but de la méthode CreateRangeCondition(OperatorType comparison, double value)
est de créer une condition de déclenchement en fonction d’une valeur étalon et d’un type de comparaison. Et en y regardant de plus près, tu verras qu’elle définit un Binding sur la valeur du VolumeTracker
tout en lui appliquant un CompareConverter.
L’idée est simple, on veut définir des conditions pour qu’elles soient remplies uniquement si le résultat de la comparaison de la valeur étalon avec la valeur détectée est vraie.
Ça va venir, pas de panique ! Imagine que l’on ait créé une condition lambda, et que cette condition n’est remplie que si la valeur détectée est supérieure ou égale à 80.
Si le volume actuel est à 50, tu es d’accord pour dire que ça ne fera rien ? Bon, et maintenant imagine que tu montes le volume à 88… Boom, ça y est ! Ta condition est désormais satisfaite et cela va logiquement déclencher quelque chose 🙂
Courage, tu y es presque ! Il ne manque plus qu’à ajouter nos trois nouveaux déclencheurs au MuteButton
. Et ça, je sais que tu sais faire ! On procède donc comme ci-après :
Nom du fichier :MusicPlayerView.cs
|
|
Voilà, c’est terminé ! Vas-y réessaye de lancer l’appli !
L’application commence sérieusement à prendre forme, j’espère que tu es fier·ère de toi !
Seulement… tout ce qu’on a pour le moment n’est que visuel. Rien ne se passe vraiment quand on manipule tous les boutons !
Rassure-toi, tu es maintenant prêt·e pour développer les fonctionnalités clés de l’appli, dès le prochain chapitre !
Plus d’articles dans la même série: