French Comment font-ils ? #1

Informatix

Expert
Licensed User
Longtime User
Comment font-ils ? #1

Ce tutoriel est le premier d'une série qui va vous montrer comment reproduire certaines interfaces utilisateur (IU) avec les classes et les bibliothèques disponibles avec B4A. Le but principal est de vous montrer comment exploiter au mieux les outils mis à votre disposition. Je n'ai pas la prétention de vous apprendre à concevoir des interfaces utilisateur et je vous épargnerai toute théorie sur le sujet. Je ne suis pas designer professionnel. Il y a probablement des méthodes alternatives à celles présentées ici qui sont tout aussi bien.

J'ai choisi les interfaces à reproduire pour des raisons diverses. Leur point commun est d'être de qualité professionnelle. J'ai volontairement écarté les interfaces des jeux, qui sont un cas à part, et je ne discuterai pas de la qualité, de l'efficacité ou de l'attrait visuel de ces interfaces.

Je précise que je n'ai pas fait de reverse engineering; j'ignore donc la méthode exacte qu'ont employée les auteurs de ces IU, et j'ai reproduit les graphismes à partir des copies d'écran (merci à l'inventeur du copier/coller). Pour des raisons de droits d'auteur, il n'y aura rien à télécharger dans cet article.

Nous allons commencer par Hotmail de Microsoft et, plus précisément, sa liste de messages. C'est une interface sobre et classique:
attachment.php


Nous voyons que l'interface est composée d'une liste qui n'est pas un Listview (un Listview ne nous permet pas d'ajouter une case à cocher et est limité à deux Labels) et qu'au-dessus de cette liste il y a une barre d'onglets. Nous sommes donc face à un TabHost hébergeant un Scrollview. Juste en dessous de la barre d'onglets, il y a un en-tête indiquant quel dossier de la messagerie est actuellement affiché. C'est un Label qui ne fait pas partie du Scrollview. Dans les autres pages, par contre, il y est incorporé. Je montrerai cette variante à la fin. Pour l'instant, j'ouvre le désigner de B4A et je crée mon TabHost. Je crée par dessus un Panel composé d'un Label et d'un Scrollview:
attachment.php


Dans l'éditeur de script, je tape le code plaçant et dimensionnant les objets. Le TabHost occupe tout l'écran. Le Label et le ScrollView se partagent le Panel. Le Label est de hauteur fixe.

B4X:
'All variants script
TabHost1.Height = 100%y
TabHost1.Width = 100%x

'Vues du Panel1
Label1.Top = 0
Label1.Left = 0
Label1.Width = 100%x
Label1.Height = 30dip
ScrollView1.Top = Label1.Height
ScrollView1.Height = 100%y - ScrollView1.Top
ScrollView1.Width = 100%x

Je sauvegarde cet écran sous le nom TabMsg.bal.

Dans la sub Activity_Create, je charge l'écran dans l'activité et j'insère le Panel dans le TabHost:
B4X:
Sub Globals
   Dim TabHost1 As TabHost
   Dim Panel1 As Panel
   Dim Label1 As Label
   Dim ScrollView1 As ScrollView
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("TabMsg.bal")

   Dim bmpDefault, bmpSelected As Bitmap
   bmpDefault = LoadBitmap(File.DirAssets, "envel_orange.png")
   bmpSelected = bmpDefault
   Panel1.RemoveView
   TabHost1.AddTabWithIcon2("Hotmail", bmpDefault,  bmpSelected, Panel1)
End Sub
Comme j'avais créé le Panel dans le designer, il est rattaché au départ à l'activité. Je dois le détacher de son parent pour pouvoir le rattacher au TabHost, d'où le RemoveView. Une fois dans le TabHost, le Panel est automatiquement placé et dimensionné.
Pour ajouter une icône dans l'onglet, j'utilise la fonction AddTabWithIcon2. Comme l'icône est la même quel que soit l'état de l'onglet, je la charge une seule fois en mémoire (bmpSelected pointe sur bmpDefault).

Je rajoute maintenant les autres onglets. Comme je n'ai pas créé de contenu pour ces onglets, je crée un Panel colorié en blanc pour les remplir: DummyPanel. Dans cet exemple, je ne me soucie pas des icônes.

B4X:
Dim DummyPanel As Panel
DummyPanel.Initialize("")
DummyPanel.Color = Colors.White
TabHost1.AddTab2("Home", DummyPanel)
TabHost1.AddTab2("All emails", DummyPanel)
   
Dim bmpDefault, bmpSelected As Bitmap
bmpDefault = LoadBitmap(File.DirAssets, "envel_orange.png")
bmpSelected = bmpDefault
Panel1.RemoveView
TabHost1.AddTabWithIcon2("Hotmail", bmpDefault,  bmpSelected, Panel1)
   
TabHost1.AddTab2("School", DummyPanel)
TabHost1.AddTab2("Search", DummyPanel)
J'écris le texte en gras dans le Label et je colorie son fond en gris bleuté:
B4X:
Label1.Text = " Hotmail - Inbox"
Label1.Typeface = Typeface.DEFAULT_BOLD
Label1.Color = Colors.RGB(124, 133, 148) 'Bluish gray
Voyons voir le résultat. On se rend compte qu'il y a une marge indésirable autour du TabHost et autour du Panel. Ma barre d'onglets est trop grande et la couleur des onglets ne correspond pas au modèle.
attachment.php


Je vais utiliser la bibliothèque TabHostExtras pour modifier tout ça. Je la coche dans les Libs de B4A et j'ajoute dans Globals:
B4X:
   Dim THExtras As TabHostExtras
Puis dans Activity_Create:
B4X:
THExtras.setTabHeight(TabHost1, 62dip)
THExtras.setTabHostPadding(TabHost1, 0, 0, 0, 0)
THExtras.setTabContentViewPadding(TabHost1, 0, 0, 0, 0)
THExtras.setTabTextColorStateList(TabHost1, "tab_widget_text_colors")
La fonction setTabTextColorStateList fait référence à un fichier XML que j'ai placé dans le répertoire Objects/res/drawable de mon projet. J'ai protégé ce fichier en écriture pour que B4A ne puisse pas l'effacer. Voici son contenu:
B4X:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:state_selected="true"
      android:color="#FFFFFF" />
   <item android:state_selected="false"   
      android:color="#606060" />
</selector>
Je différencie les couleurs (android:color) suivant l'état sélectionné ou non (android:state_selected) de l'onglet.

Reste à colorier le fond de l'onglet. Là, les choses se compliquent car TabHostExtras v2.0 n'a pas de fonction adéquate. Je dois donc soit écrire une bibliothèque pour combler le manque, soit faire appel à l'API d'Android avec la bibliothèque Reflection. Je choisis cette deuxième solution. J'ajoute dans Activity_Create:
B4X:
Dim cdEnabled, cdSelected As ColorDrawable
cdEnabled.Initialize(Colors.Black, 0)
cdSelected.Initialize(Colors.Gray, 0)
Dim r As Reflector
r.Target = TabHost1
r.Target = r.RunMethod("getTabWidget")
For t = 0 To TabHost1.TabCount - 1
   Dim TabPanel As Panel
   TabPanel = r.RunMethod2("getChildAt", t, "java.lang.int")
   Dim sd As StateListDrawable
   sd.Initialize
   sd.AddState(sd.State_Selected, cdSelected)
   sd.AddState(sd.State_Pressed, LoadDrawable("highlight_pressed"))
   sd.AddState(sd.State_Enabled, cdEnabled)
   TabPanel.Background = sd
Next
Dans ce code, je fais appel à la fonction LoadDrawable. Elle sert à récupérer un drawable du système par son nom. Le SDK d'Android contient une copie de ces drawables dans le répertoire C:\Android\android-sdk\platforms\android-n\data\res\. Ils peuvent différer légèrement de ceux installés sur votre appareil.
B4X:
Sub LoadDrawable(Name As String) As Object
   Dim r As Reflector
   r.Target = r.GetContext
   r.Target = r.RunMethod("getResources")
   r.Target = r.RunMethod("getSystem")
   Dim ID_Drawable As Int
   ID_Drawable = r.RunMethod4("getIdentifier", Array As Object(Name, "drawable", "android"), _
                                               Array As String("java.lang.String", "java.lang.String", "java.lang.String"))
   r.Target = r.GetContext
   r.Target = r.RunMethod("getResources")
   Return r.RunMethod2("getDrawable", ID_Drawable, "java.lang.int")
End Sub
Ajoutons la petite barre ombrée sous les onglets:
B4X:
Dim ivShadow As ImageView
ivShadow.Initialize("")
ivShadow.Background = LoadDrawable("code_lock_bottom")
Panel1.AddView(ivShadow, 0, 0, 100%x, 5dip)
Le résultat est maintenant très proche du modèle:
attachment.php


Occupons-nous du ScrollView. Pour créer la liste, je vais utiliser la classe CheckList. Je copie son fichier bas dans le répertoire du projet et je la déclare dans Globals:
B4X:
   Dim MsgList As ClsCheckList
Puis je l'initialise dans Activity_Create:
B4X:
   MsgList.Initialize(Me, ScrollView1, "", "Msg_Click", "", 2dip)
Chaque item de la liste est composé d'une case à cocher, d'une petite image optionnelle (le trombone) et de trois étiquettes (auteur, sujet, date d'envoi). J'ouvre le designer et je crée le masque item.bal:
attachment.php

Script du masque:
B4X:
'All variants script
Label1.Width = 100%x - 85dip
Label2.Width = 100%x - 130dip
Label3.Left = 100%x - Label3.Width - 5dip
ImageView1.Left = 100%x - ImageView1.Width – 5dip
Je crée une routine qui va remplir ce masque:
B4X:
Sub FillItem(MsgSender As String, MsgSubject As String, MsgDate As String, MsgRead As Boolean, MsgAttached As Boolean) As Panel
   Dim pnl As Panel
   pnl.Initialize("")
   pnl.LoadLayout("item.bal")

   If MsgRead Then
      pnl.Color = Colors.Black
   Else
      pnl.Color = Colors.DarkGray 'Unread messages have a gray background
   End If

   Dim lblSender, lblSubject, lblDate As Label
   lblSender = pnl.GetView(1)
   lblSender.Text = MsgSender

   lblSubject = pnl.GetView(2)
   lblSubject.Text = MsgSubject

   lblDate = pnl.GetView(3)
   lblDate.Text = MsgDate

   Dim ivAttached As ImageView
   ivAttached = pnl.GetView(4)
   ivAttached.Visible = MsgAttached

   Return pnl
End Sub
Pour vérifier le résultat final, je remplis ma liste avec du contenu:
B4X:
Dim pnl As Panel
pnl = FillItem("John Smith", "Hello Fred", "22:26", True, False)
MsgList.AddCustomItem("ID#100", pnl, 60dip)
pnl = FillItem("Lisa Gray", "I'm still loving you", "22:26", False, False)
MsgList.AddCustomItem("ID#101", pnl, 60dip)
pnl = FillItem("Darth Vador", "I'm your father", "09/08/2011", False, False)
MsgList.AddCustomItem("ID#102", pnl, 60dip)
pnl = FillItem("Pamela Rose", "FW: Class ChkList", "09/08/2011", True, True)
MsgList.AddCustomItem("ID#103", pnl, 60dip)

MsgList.ResizePanel
Et voilà:
attachment.php


Variante:
Dans la page All Emails, le Label d'en-tête n'est pas fixe. Il fait partie du Scrollview et défile avec lui. Pour faire cela, il faut retirer le Label du Panel dans le designer et donner l'espace libéré au Scrollview. Ensuite, avant de remplir la liste, il faut créer un Panel d'en-tête, mettre le Label dedans et ajouter ce Panel à la liste avec AddCustomItem (hauteur 30dip).

Comment font-ils ? #2 >>>

L'auteur: Frédéric Leneuf-Magaud. Je suis développeur professionnel depuis le début des années 90 et j'ai conçu ou participé à une centaine d'applications. Je travaille actuellement pour l'administration française dans une équipe de supervision de serveurs. Le développement sous Android fait partie de mes loisirs.
 

Attachments

  • Hotmail1.png
    Hotmail1.png
    63 KB · Views: 4,478
  • Hotmail2.png
    Hotmail2.png
    13.2 KB · Views: 4,324
  • Hotmail3.png
    Hotmail3.png
    10.4 KB · Views: 4,305
  • Hotmail4.png
    Hotmail4.png
    30.2 KB · Views: 4,367
  • Hotmail5.png
    Hotmail5.png
    28.4 KB · Views: 4,362
  • Hotmail.jpg
    Hotmail.jpg
    33.6 KB · Views: 4,400
Last edited:

logemag

Member
Licensed User
Longtime User
merci !

merci encore pour ces explications, du coup ça m'a donné envie d'ajouter une ClsCheckList à mon projet pour pouvoir passer plus d'info que dans une tableview. En plus on peut créer des effets assez sympa, grâce aux couleur des labels... Allez j'envoie un petit screen de mon boulot du week end, pour montrer l'intégration d'une liste optimisée :




Bon le projet est loin d'être terminé, j'ai pas mis encore de boutons perso, ni potassé le graphisme ni les textes, mais pour faire simple c'est l'extension sur tablette de notre log PC sous VB, pour la prise de commande dans un bar - resto, le log télécharge la base de donnée (articles, vendeurs, couleurs, catégories etc...), les infos sont ensuite envoyés au PC pour être traitées, avec possibilité de renvoi en cuisine, gestion des accompagnements etc...

Suivra ensuite une version autonome pour PC android X86, avec impression des tickets par USB ou wifi... avec création d'articles, possibilité de gestion de stock pour la version tout commerce etc... tout un programme !

En tout cas bravo pour ces tutos, j'ai aussi vu le deuxième, c'est vrai que c'est important le layout, et l'intégration graphique dans un projet...
 

logemag

Member
Licensed User
Longtime User
J'avais dans l'idée de rajouter des boutons par ligne qui + et - de chaque coté de quantité, mais après un bref essai, je trouvais que ça alourdissait trop la grille, et en plus je ne savais pas trop comment faire pour faire passer les infos, mais je suis preneur pour d'autres tutos, c'est toujours très intéressant...

Je commence juste à ajouter des images en 9-patch sur mes boutons, pour que ceux -ci puissent être cohérents du 7" au 15", j'ai galéré un moment avant de comprendre vraiment le fonctionnement mais les derniers essais sont prometteurs. Merci encore pour les tutos en français, même si on comprend la langue de shakespeare, c'est quand même plus facile à assimiler pour la communauté francophone.
 
Top