I. Introduction▲
Cet article, pour assurer un maximum de lisibilité, a été écrit en trois parties que nous rappellerons toujours en introduction. S'il s'agit d'un retour d'expérience, c'est aussi un petit guide pour vous aider à bien démarrer sur Android Wear avec Xamarin.
- Xamarin et Android Wear - Partie 1 : les bases indispensables pour bien démarrer
- Xamarin et Android Wear - Partie 2 : l'apparence visuelle en détail
- Xamarin et Android Wear - Partie 3 : poser les briques d'une application évoluée
II. Par où commencer ?▲
Quand on est habitué à la plateforme Windows (Phone) Store de Microsoft, nous avons une approche logique qui, tout en prônant lisibilité, clarté, fluidité, sobriété, peut ne pas forcément convenir, car bien entendu, il faut s'intégrer à la plateforme cible. S'intégrer à la plateforme, cela veut dire, l'appréhender ou tout simplement, la connaître pour satisfaire aux exigences du constructeur.
II-A. Utiliser l'appareil et ses applications▲
Créer une application à destination d'un appareil impose au moins de le connaître. Et par la suite, savoir l'utiliser, utiliser ses applications. C'est vrai que je ne connaissais que de loin la LG G Watch, et il a fallu quelque temps d'adaptation pour savoir correctement l'utiliser. Comprendre la navigation hiérarchique avec son menu caché tout en haut à droite, comprendre l'utilisation de la voix, son intégration, comprendre la navigation au sein des menus, la navigation au sein des applications, la navigation au sein des notifications, etc. Bref, c'est le minimum pour en avoir une bonne approche, un premier aperçu. Il est vrai que l'on ne pourra pas tester l'intégralité des applications existantes (même si elles ne sont point encore légion), mais elles peuvent donner un aperçu du potentiel graphique, visuel, ou plutôt de ce qui a été fait. Attention toutefois, car les applications système ne sont pas forcément les plus évoluées visuellement sur Android Wear.
II-B. Le site développeur pour les designers▲
Je ne suis pas/plus designer, mais j'aime développer des choses dans l'esprit des plateformes cibles. Rechercher chez Google était donc pour moi indispensable. J'avoue avoir été agréablement surpris par ce que j'ai pu trouver sur le site développeurs de Google, non seulement des sections propres aux développeurs, à la distribution des applications, mais aussi au design.
Design des applications Android Wear : https://developer.android.com/design/wear/index.html.
Si vous désirez pousser un peu plus loin et vous familiariser avec le Material Design, c'est par ici : https://developer.android.com/design/material/index.html.
II-C. Android Wear Materials▲
Si vous souhaitez un accès direct aux ressources qui m'ont le plus servi pour ce projet, voici le lien : https://developer.android.com/design/downloads/index.html#Wear.
J'ai pu y retrouver :
- un guide Toolkit de l'interface utilisateur (UI toolkit) regroupant certaines conventions de nommage, mais aussi des mesures des espaces/positionnements de certains composants de base Android Wear, ainsi que quelques codes couleur ;
- quelques exemples de pattern de navigation depuis une notification ou une application (Sample user flow patterns), document très pratique pour rapidement voir des cas pratiques qui, même s'ils sont peu nombreux, sont clairs et efficaces ;
- quelques mocks pour rapidement créer des visuels de son application (Sample app design mocks).
En dessous de cette section « Wear », il y a une section « Style » avec la police d'écriture principale (Roboto) et ses bonnes pratiques d'utilisation, ainsi que les couleurs qu'il est possible d'utiliser principalement pour rester au maximum le plus proche de l'identité visuelle idéale.
Quelques manques importants toutefois. Je suis sensible à l'iconographie, vous savez, l'ensemble des ressources graphiques, visuelles pour le marketing de votre application, et ce n'est pas quelque chose que j'ai trouvé sur le site de Google. Il y a cependant une petite section iconographie, une autre relative au branding (votre marque) et quelques conseils d'ordre général dans la section Distribute, spécialement pour tout ce qui est wearable. Ces ressources sont un peu éparses et j'aurai préféré les retrouver dans un seul et même document comme Nathalie a déjà pu le faire via son magnifique Windows Phone DESIGN GUIDELINES cheat sheet. Si ça se trouve, elle nous prépare une surprise aussi de ce côté-là :-).
III. Contrôles et usages▲
J'en parlais déjà dans la première partie de ce dossier, Android Wear est une version d'Android spécifique, la version 4.4Wx. Cela veut dire que l'on a un accès à tous les contrôles Android existants et qu'il serait possible de les utiliser. Mais bien entendu, l'usage de certains de ces contrôles ne convient pas toujours, car Android Wear se veut optimisé pour ces appareils à faible puissance. Optimisé ne veut pas seulement dire meilleur en termes de performance, mais aussi meilleur en termes d'adaptabilité et d'usage pour l'appareil ou le système hôte. Si quelques contrôles se prêtent donc bien à ce jeu de compatibilité comme les labels (TextView), images (ImageView), ou encore les boutons (Button), d'autres ne sont tout simplement pas adaptés, ni même compatibles comme l'ActionBar, ou les sélecteurs comme les Spinners, les layouts comme les ListView, GridView, etc. Cela signifie qu'il risque d'y avoir plus d'efforts à fournir pour obtenir un résultat visuel intéressant. Google semble ici vouloir pousser l'utilisation d'autres contrôles spécifiques que nous verrons ensemble.
III-A. Les layouts▲
Les layouts définissent la structure visuelle pour une interface utilisateur. Une problématique importante quand on développe pour Android Wear est qu'il y a deux facteurs de formes à cibler, les appareils à forme carrée et à forme ronde. Si donc les habituels LinearLayout et RelativeLayout sont toujours utilisés, de nouveaux contrôles apparaissent afin d'aider à mieux décrire les apparences de vos applications et gérer ces deux formes. Et c'est une nécessité, au risque de se retrouver avec une apparence pouvant ressembler à ça :
Bon, je l'admets, j'ai volontairement fait en sorte que ça ne fonctionne pas sur les deux types d'écrans, mais ça fonctionnait par défaut.
III-A-1. Gestion du layout « manuelle » avec le WatchViewStub▲
Si nous avions été habitués aux qualificatifs suffixés de type layout-sw600dp pour la gestion de différents types d'écran, la gestion des vues ciblant les différents types d'appareils peut être faite avec le contrôle WatchViewStub. Ce contrôle permet, pour une vue spécifique, de préciser via deux attributs, rectLayout et roundLayout, les chemins relatifs aux vues pour la forme carrée, et une autre pour la forme ronde. Cela se gère simplement comme ceci :
<android.support.wearable.view.WatchViewStub
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
xmlns
:
app
=
"http://schemas.android.com/apk/res-auto"
xmlns
:
tools
=
"http://schemas.android.com/tools"
android
:
id
=
"@+id/watch_view_stub"
android
:
layout_width
=
"match_parent"
android
:
layout_height
=
"match_parent"
app
:
rectLayout
=
"@layout/rect_main_activity_wear"
app
:
roundLayout
=
"@layout/round_main_activity_wear"
>
</android.support.wearable.view.WatchViewStub>
Libre aux développeurs (ou intégrateurs) de créer des vues spécifiques pour chaque forme et de les lier à la vue principale avec le WatchViewStub.
Voici un exemple de rendu avec ce contrôle :
On peut remarquer au premier coup d'œil que selon l'écran, le visuel est adapté. Bien entendu, cela dépendra aussi de la façon dont le visuel est géré, si les éléments visuels s'adaptent au parent ou pas, si des attributs de tailles fixes ne sont également pas utilisés.
Il existe une autre façon de procéder, utiliser un autre contrôle, mais qui offre d'autres possibilités, c'est le BoxInsetLayout.
III-A-2. BoxInsetLayout▲
Si l'on utilise le même layout que ceux que j'ai utilisés précédemment avec le BoxInsetLayout, le rendu sera strictement le même. Voici un exemple de code montrant comment l'utiliser :
<android.support.wearable.view.BoxInsetLayout
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
background
=
"@drawable/dual_sided_bird_thermometer"
xmlns
:
app
=
"http://schemas.android.com/apk/res-auto "
android
:
layout_height
=
"match_parent"
android
:
layout_width
=
"match_parent"
android
:
padding
=
"10dp"
>
<FrameLayout
android
:
layout_width
=
"match_parent"
android
:
layout_height
=
"match_parent"
android
:
padding
=
"5dp"
app
:
layout_box
=
"all"
>
// YOUR UI CODE
</FrameLayout>
</android.support.wearable.view.BoxInsetLayout>
Mais quel intérêt d'utiliser l'un ou autre ? Notre contrôle a ici un attribut layout_box, qui rajoute une possibilité supplémentaire, celle de prendre en compte une zone de fenêtre fixe. L'intérêt réel est de forcer un affichage identique, et ce, peu importe le facteur de forme. Je peux vouloir par exemple que ma zone d'affichage reste coûte que coûte carrée. C'est ainsi tout l'intérêt de ce contrôle.
C'est vrai que l'affichage n'est pas adapté à notre écran, mais le rendu visuel est contenu dans un carré avec une marge extérieure. Tout cela est rendu possible grâce en partie à l'attribut layout_box qui permettra d'influer sur la façon dont les éléments enfants sont positionnés dans la zone fenêtrée. Pour en savoir plus, vous pouvez lire la documentation sur le sujet présentant son utilisation.
III-B. La gestion des listes▲
Durant mon projet, ça a été un point assez sensible et bloquant que je n'ai pas réussi à résoudre. Le SDK Android Wear embarque un contrôle optimisé pour les périphériques portables, le WearableListView. Si son utilisation semble simple, il n'a malheureusement pas été possible pour moi de l'utiliser pendant mon projet. Et pour cause, son support est mal assuré dans le SDK Wearable créé par Xamarin. J'ai remonté ce problème il y a quelque temps, et il n'y a pas encore de nouvelles versions du SDK proposant un bug fix (en fait, une nouvelle version est sortie, mais je ne l'ai pas encore testée), mais un workaround récent que je n'ai pas eu l'occasion de tester. Dès qu'il sera possible de l'utiliser de façon officielle, je reviendrai sans aucun doute là-dessus. Je pouvais me rabattre sur les ListView classiques, mais cela me demanderait trop d'efforts sur l'optimisation (tactile, visuelle, etc.).
III-C. Les cards▲
Bien qu'elle ne soit plus très récente, la notion de card avait été complètement nouvelle pour moi, même si j'en avais déjà vu quelques visuels. En termes très simples, une card est un container visuel avec un titre, une description et éventuellement, une icône. Ce container a une apparence particulière par défaut, c'est un rectangle de fond blanc avec des bords arrondis, une légère bordure et une légère ombre. L'avantage de ce conteneur est qu'il ne demande aucun style particulier et fournit déjà les éléments nécessaires à sa constitution.
Pour les intégrer à vos layouts, il y a deux façons de procéder.
La première consiste à passer par le code C#, dans le code behind de votre vue, et créer une instance de l'objet CardFragment (ou en passant par la méthode statique de l'objet CardFragment).
CardFragment.
Create (
"Greetings"
,
"Hello World !"
,
Resource.
Drawable.
Icon) ;
La seconde méthode est d'utiliser dans vos layouts le contrôle CardFrame :
<android.support.wearable.view.BoxInsetLayout
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
xmlns
:
app
=
"http://schemas.android.com/apk/res-auto"
android
:
background
=
"@drawable/dual_sided_bird_thermometer"
android
:
layout_height
=
"match_parent"
android
:
layout_width
=
"match_parent"
>
<android.support.wearable.view.CardScrollView
android
:
id
=
"@+id/card_scroll_view"
android
:
layout_height
=
"match_parent"
android
:
layout_width
=
"match_parent"
app
:
layout_box
=
" all"
>
<android.support.wearable.view.CardFrame
android
:
layout_height
=
"wrap_content"
android
:
layout_width
=
"fill_parent"
android
:
layout_gravity
=
"bottom"
>
<LinearLayout
android
:
layout_height
=
"wrap_content"
android
:
layout_width
=
"fill_parent"
android
:
orientation
=
"vertical"
>
<TextView
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"Welcome"
android
:
textSize
=
"26dp"
android
:
fontFamily
=
"sans-serif-bold"
android
:
layout_gravity
=
"center|center_horizontal|center_vertical"
android
:
gravity
=
"center|center_vertical|center_horizontal"
/>
<TextView
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"Press the magic button"
android
:
textSize
=
"18dp"
android
:
fontFamily
=
"sans-serif-light"
android
:
padding
=
"5dp"
android
:
layout_gravity
=
"center|center_horizontal|center_vertical"
android
:
gravity
=
"center|center_vertical|center_horizontal"
/>
<Button
android
:
id
=
"@+id/runSpeechRButton"
android
:
layout_width
=
"70dp"
android
:
layout_height
=
"70dp"
android
:
background
=
"@drawable/mic_icon"
android
:
layout_gravity
=
"center_horizontal|center_vertical"
/>
</LinearLayout>
</android.support.wearable.view.CardFrame>
</android.support.wearable.view.CardScrollView>
</android.support.wearable.view.BoxInsetLayout>
Quand utiliser l'une ou l'autre solution ?
Si vous souhaitez créer une card personnalisée, alors, utiliser l'option CardFrame est préférable. Autrement, via le code C#, ce sera suffisant.
Pour en savoir plus, je vous invite à consulter la documentation en ligne sur la création des Cards pour Android Wear.
III-D. Navigation alternative avec le 2D Picker▲
Quand on utilise Android Wear et que vous synchronisez votre montre avec votre téléphone ou votre tablette, il est fort probable que vous y receviez des notifications. Et il est possible d'interagir avec ces notifications via un système de navigation que l'on appelle le pattern 2D Picker. Ce pattern qui s'utilise avec un contrôle spécifique, le GridViewPager permet de créer une liste de listes de pages (des CardFragments).
Il y a des recommandations quant à la façon de naviguer vers les différentes options (pages) que vous avez créées, et il est indispensable de les consulter. Au risque de perdre l'utilisateur dans une navigation à laquelle il ne serait pas familier.
Son utilisation reste très simple :
<? xml version= "1.0" encoding= "utf-8" ?>
<FrameLayout
xmlns
:
android
=
" http://schemas.android.com/apk/res/android "
android
:
background
=
"#fafafa"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"fill_parent"
>
<android.support.wearable.view.GridViewPager
android
:
id
=
"@+id/gvPager"
android
:
layout_width
=
"match_parent"
android
:
layout_height
=
"match_parent"
/>
</FrameLayout>
Toutefois, avec Xamarin (mais à cause du SDK Google cette fois-ci)… il y a un bogue assez sérieux empêchant d'utiliser correctement le GridViewPager lorsque l'on assigne son adaptateur (bogue que j'avais pris le soin de signaler). Le GridViewPager a besoin d'une liste d'éléments fournis à son adaptateur pour fonctionner. Le problème était que, au moment d'instancier l'adapter de façon classique à la création de la vue, une erreur était générée. Un workaround m'a été suggéré en quelques étapes :
- Changer la visibilité du GridViewPager par défaut à gone (afin qu'il n'existe pas dans l'arbre visuel) ;
- Créer son instance dans l'évènement OnCreate de la vue ;
- Lors de l'évènement OnStart, instancier l'adaptateur ;
- Changer la visibilité du GridViewPager à Visible.
Cela nécessite quelques efforts supplémentaires, mais a le mérite de fonctionner en attendant que Google puis Xamarin fassent les mises à jour nécessaires.
La création des options du contrôle a été un peu fastidieuse je dois avouer. Nous y reviendrons dans le prochain article sur la conception de notre application.
III-E. Les confirmations▲
Avec Android Wear, il y a des comportements ou des contrôles que l'on appelle Confirmation. Ces contrôles peuvent utiliser l'intégralité de l'écran de l'appareil ou une portion et permettent à l'utilisateur d'avoir une surface suffisamment grande pour interagir avec l'application pour une action particulière. On retrouvera deux notions de confirmations : les confirmations chronométrées (confirmation timers) et les confirmations animées (confirmation animations). La documentation officielle est assez claire sur le sujet et sur leur utilisation, et le code est facilement adaptable à Xamarin. Je vous propose d'y revenir dans notre prochain article.
IV. Et l'application du contexte ?▲
L'application n'était pas difficile en soi, sauf pour la partie visuelle bien entendu. J'avais plusieurs fonctionnalités, plusieurs écrans auxquels je souhaitais accéder. Dans un premier temps, j'ai suggéré l'utilisation des commandes vocales (pratiques, mais insuffisantes en milieu événementiel ou l'on peut se retrouver avec beaucoup de bruits d'ambiance). L'impossibilité d'utiliser une simple liste comme la WearListView m'a obligé à créer un menu simple devenu complexe avec le GridViewPager, mais qui a fait l'affaire finalement.
V. Conclusion▲
Voilà, nous avons pu faire le tour en bref de ce qu'il faut savoir pour pouvoir concevoir notre application visuellement. Certaines choses peuvent vous faire perdre un peu de temps, c'est ce que nous avons évoqué ici avec notamment les listes ou le 2D Picker. Il existe cependant des solutions pour parvenir à nos fins. C'est donc maintenant que la partie la plus intéressante pour les développeurs débute), celle qui nous permet de rentrer dans le cœur du sujet, la construction des briques importantes de notre application Android Wear.
VI. Remerciements▲
Cet article a été publié avec l'aimable autorisation de SOAT, société d'expertise et de conseil en informatique.
Nous tenons à remercier Claude LELOUP pour la relecture orthographique et Marie-Hélène Delacroix pour la mise au gabarit.