🔝 Retour au Sommaire
L'interface tactile a révolutionné la façon dont les utilisateurs interagissent avec les applications. Contrairement à une souris qui permet une précision au pixel près, un doigt est moins précis mais offre des interactions plus naturelles et intuitives. Concevoir une interface utilisateur tactile efficace nécessite de comprendre ces différences et d'adapter votre approche de conception en conséquence.
Dans cette section, nous allons explorer comment créer des interfaces utilisateur adaptées au tactile avec Delphi et FireMonkey, en respectant les bonnes pratiques et en offrant une expérience utilisateur optimale.
Avec une souris, le curseur est représenté par un point précis à l'écran. L'utilisateur peut cliquer sur de très petits éléments (quelques pixels) sans difficulté.
Avec le doigt, la zone de contact est beaucoup plus large (environ 8-10mm de diamètre). De plus, le doigt cache partiellement l'élément sur lequel l'utilisateur appuie, ce qui rend l'interaction moins précise.
Règle d'or : Les éléments interactifs (boutons, liens, contrôles) doivent mesurer au minimum 44x44 points (environ 7-9mm), et idéalement 48x48 points pour être confortables à utiliser.
// Dans Delphi, définir une taille minimale pour un bouton
procedure TFormMain.ConfigurerBouton(Bouton: TButton);
begin
Bouton.Width := 48; // En points (pixels indépendants)
Bouton.Height := 48;
Bouton.Text := 'OK';
end;Sur mobile, il est crucial de laisser suffisamment d'espace entre les éléments interactifs pour éviter les clics accidentels. Un espacement de 8 à 16 points minimum entre les boutons est recommandé.
// Positionner des boutons avec un espacement approprié
procedure TFormMain.CreerBoutonsEspaces;
begin
Bouton1.Position.Y := 100;
Bouton2.Position.Y := Bouton1.Position.Y + Bouton1.Height + 12; // Espacement de 12 points
Bouton3.Position.Y := Bouton2.Position.Y + Bouton2.Height + 12;
end;L'utilisateur doit recevoir un retour visuel instantané lorsqu'il touche un élément. Sans le survol de la souris, ce feedback est encore plus important sur mobile.
// Changer l'apparence d'un bouton lors de l'appui
procedure TFormMain.BoutonMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Single);
begin
TButton(Sender).Opacity := 0.7; // Réduire l'opacité
end;
procedure TFormMain.BoutonMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Single);
begin
TButton(Sender).Opacity := 1.0; // Restaurer l'opacité
end;Les utilisateurs mobiles s'attendent à pouvoir utiliser des gestes naturels dans vos applications.
C'est l'équivalent du clic de souris. L'utilisateur touche brièvement un élément pour l'activer.
// Gérer un simple toucher
procedure TFormMain.ImageTap(Sender: TObject; const Point: TPointF);
begin
ShowMessage('Image touchée à la position: ' +
Point.X.ToString + ', ' + Point.Y.ToString);
end;L'utilisateur maintient son doigt sur un élément pendant une seconde ou plus. Cela sert souvent à afficher un menu contextuel ou des options supplémentaires.
uses
FMX.Gestures;
// Configurer la détection d'appui long
procedure TFormMain.FormCreate(Sender: TObject);
begin
Image1.Touch.GestureManager := GestureManager1;
Image1.Touch.InteractiveGestures := [TInteractiveGesture.LongTap];
end;
// Gérer l'appui long
procedure TFormMain.Image1Gesture(Sender: TObject;
const EventInfo: TGestureEventInfo; var Handled: Boolean);
begin
if EventInfo.GestureID = igiLongTap then
begin
ShowMessage('Appui long détecté !');
Handled := True;
end;
end;L'utilisateur glisse rapidement son doigt dans une direction (gauche, droite, haut, bas). Ce geste est couramment utilisé pour naviguer entre des écrans ou supprimer des éléments.
// Activer la détection de swipe
procedure TFormMain.ConfigurerSwipe;
begin
Panel1.Touch.GestureManager := GestureManager1;
Panel1.Touch.InteractiveGestures := [TInteractiveGesture.Left,
TInteractiveGesture.Right];
end;
// Gérer le swipe
procedure TFormMain.Panel1Gesture(Sender: TObject;
const EventInfo: TGestureEventInfo; var Handled: Boolean);
begin
case EventInfo.GestureID of
igiLeft:
begin
// Swipe vers la gauche - aller à l'écran suivant
AfficherEcranSuivant;
Handled := True;
end;
igiRight:
begin
// Swipe vers la droite - retourner à l'écran précédent
AfficherEcranPrecedent;
Handled := True;
end;
end;
end;L'utilisateur utilise deux doigts pour zoomer (écarter) ou dézoomer (pincer). Ce geste est essentiel pour les images, les cartes et les documents.
// Configurer le zoom par pincement
procedure TFormMain.ConfigurerZoom;
begin
Image1.Touch.GestureManager := GestureManager1;
Image1.Touch.InteractiveGestures := [TInteractiveGesture.Zoom];
end;
// Gérer le zoom
// On stocke la distance précédente entre les deux doigts dans un champ
// privé du formulaire (FDistancePrecedente: Single) pour pouvoir
// calculer un facteur d'échelle relatif à chaque mouvement.
procedure TFormMain.Image1Gesture(Sender: TObject;
const EventInfo: TGestureEventInfo; var Handled: Boolean);
var
Facteur: Single;
begin
if EventInfo.GestureID = igiZoom then
begin
if TInteractiveGestureFlag.gfBegin in EventInfo.Flags then
begin
// Début du geste : on mémorise la distance initiale
FDistancePrecedente := EventInfo.Distance;
end
else if FDistancePrecedente > 0 then
begin
// Mouvement : on applique un facteur proportionnel
Facteur := EventInfo.Distance / FDistancePrecedente;
Image1.Scale.X := Image1.Scale.X * Facteur;
Image1.Scale.Y := Image1.Scale.Y * Facteur;
FDistancePrecedente := EventInfo.Distance;
end;
Handled := True;
end;
end;L'utilisateur fait défiler le contenu en glissant son doigt verticalement ou horizontalement. FireMonkey gère automatiquement le scroll avec les composants TVertScrollBox et THorzScrollBox.
// Créer une zone de défilement vertical
procedure TFormMain.CreerZoneDefilement;
var
ScrollBox: TVertScrollBox;
i: Integer;
begin
ScrollBox := TVertScrollBox.Create(Self);
ScrollBox.Parent := Self;
ScrollBox.Align := TAlignLayout.Client;
// Ajouter du contenu qui dépasse la hauteur visible
for i := 1 to 20 do
begin
var Btn := TButton.Create(ScrollBox);
Btn.Parent := ScrollBox;
Btn.Text := 'Bouton ' + i.ToString;
Btn.Position.Y := (i - 1) * 60;
Btn.Width := 200;
Btn.Height := 48;
end;
end;Les appareils mobiles existent dans une multitude de tailles et de résolutions. Votre interface doit s'adapter élégamment à toutes ces variations.
Les Anchors (ancres) permettent à vos contrôles de s'adapter automatiquement lorsque la taille du formulaire change.
// Ancrer un bouton en bas à droite
procedure TFormMain.ConfigurerAnchors;
begin
BoutonValider.Anchors := [TAnchorKind.akRight, TAnchorKind.akBottom];
// Le bouton restera toujours en bas à droite, quelle que soit la taille de l'écran
end;La propriété Align est votre meilleure amie pour créer des layouts qui s'adaptent automatiquement.
// Créer une interface avec en-tête, contenu et pied de page
procedure TFormMain.CreerLayoutAdaptatif;
begin
// En-tête fixe en haut
PanelEntete.Align := TAlignLayout.Top;
PanelEntete.Height := 60;
// Pied de page fixe en bas
PanelPied.Align := TAlignLayout.Bottom;
PanelPied.Height := 60;
// Le contenu occupe tout l'espace restant
PanelContenu.Align := TAlignLayout.Client;
end;Votre application doit gérer à la fois le mode portrait (vertical) et paysage (horizontal).
💡
TLayoutest un simple conteneur, il n'a pas de propriétéOrientation. Pour changer la disposition selon l'orientation, on rejoue les propriétésAlign,SizeetMarginsdes contrôles enfants — ou on utilise un conteneur orientable commeTFlowLayout(avecJustify/JustifyTrailing) ouTGridLayout(avecColumnCount).
uses
FMX.Types;
// Détecter le changement d'orientation
procedure TFormMain.FormResize(Sender: TObject);
begin
if Width > Height then
AdapterInterfacePaysage
else
AdapterInterfacePortrait;
end;
procedure TFormMain.AdapterInterfacePortrait;
begin
// En portrait : image en haut, texte juste en dessous
Image1.Align := TAlignLayout.Top;
Image1.Height := 200;
Image1.Margins.Rect := RectF(10, 10, 10, 10);
MemoDescription.Align := TAlignLayout.Client;
end;
procedure TFormMain.AdapterInterfacePaysage;
begin
// En paysage : image à gauche, texte à droite (côte à côte)
Image1.Align := TAlignLayout.Left;
Image1.Width := ClientWidth / 2;
Image1.Height := 0; // ignoré quand Align = Left
Image1.Margins.Rect := RectF(10, 10, 10, 10);
MemoDescription.Align := TAlignLayout.Client;
end;💡 Sur les vrais appareils, l'orientation est aussi accessible via
Screen.Orientation(énumérationTScreenOrientation).FormResizereste le déclencheur le plus simple et fonctionne dès qu'on tourne l'écran.
Le composant TLayout est un conteneur invisible qui aide à organiser vos contrôles de manière flexible.
// Créer une grille responsive de cartes
procedure TFormMain.CreerGrilleResponsive;
var
Layout: TLayout;
i, ColCount: Integer;
begin
// Déterminer le nombre de colonnes selon la largeur
if Width < 600 then
ColCount := 1 // 1 colonne sur petit écran
else if Width < 900 then
ColCount := 2 // 2 colonnes sur écran moyen
else
ColCount := 3; // 3 colonnes sur grand écran
// Créer les cartes avec le bon nombre de colonnes
for i := 0 to 11 do
begin
Layout := TLayout.Create(Self);
Layout.Parent := FlowLayout1;
Layout.Width := (ClientWidth / ColCount) - 10;
Layout.Height := 150;
// Ajouter le contenu de la carte
end;
end;FireMonkey offre de nombreux composants spécialement conçus pour le tactile.
Le bouton est l'élément interactif le plus courant. Assurez-vous qu'il soit suffisamment grand et visible.
// Créer un bouton tactile optimal
procedure TFormMain.CreerBoutonTactile;
begin
var Btn := TButton.Create(Self);
Btn.Parent := Self;
Btn.Width := 150;
Btn.Height := 48;
Btn.Text := 'Valider';
Btn.Position.X := 100;
Btn.Position.Y := 200;
Btn.OnClick := BoutonClick;
end;Idéal pour les barres d'outils tactiles.
// Créer une barre d'outils tactile
procedure TFormMain.CreerBarreOutils;
var
BtnNouveau, BtnEditer, BtnSupprimer: TSpeedButton;
begin
// Bouton Nouveau
BtnNouveau := TSpeedButton.Create(Self);
BtnNouveau.Parent := ToolBar1;
BtnNouveau.Width := 48;
BtnNouveau.Height := 48;
BtnNouveau.StyleLookup := 'addtoolbutton'; // Style avec icône +
// Bouton Éditer
BtnEditer := TSpeedButton.Create(Self);
BtnEditer.Parent := ToolBar1;
BtnEditer.Width := 48;
BtnEditer.Height := 48;
BtnEditer.StyleLookup := 'composetoolbutton'; // Style avec icône édition
end;Parfait pour les options on/off, plus tactile qu'une case à cocher.
// Utiliser un switch pour une option
procedure TFormMain.CreerSwitch;
begin
var Switch := TSwitch.Create(Self);
Switch.Parent := Self;
Switch.Position.X := 100;
Switch.Position.Y := 150;
Switch.OnSwitch := SwitchChange;
end;
procedure TFormMain.SwitchChange(Sender: TObject);
begin
if TSwitch(Sender).IsChecked then
ShowMessage('Option activée')
else
ShowMessage('Option désactivée');
end;Pour afficher des listes d'éléments avec des interactions tactiles (swipe pour supprimer, etc.). FireMonkey propose deux mécanismes complémentaires :
1. Activer le mode édition standard (le plus simple). Quand EditMode = True, FMX affiche automatiquement un bouton « rouge » de suppression sur chaque ligne et déclenche OnDeletingItem / OnDeleteItem à la confirmation. C'est l'approche recommandée pour 90 % des cas.
procedure TFormMain.CreerListeTactile;
var
Item: TListViewItem;
i: Integer;
begin
ListView1.ItemAppearance.ItemAppearance := 'ListItemRightDetail';
ListView1.OnDeletingItem := ListView1DeletingItem;
// Ajouter quelques éléments
for i := 1 to 5 do
begin
Item := ListView1.Items.Add;
Item.Text := 'Élément ' + i.ToString;
Item.Detail := 'Description ' + i.ToString;
end;
end;
procedure TFormMain.BtnModeEditionClick(Sender: TObject);
begin
// Active/désactive l'apparition du bouton « rouge » de suppression
ListView1.EditMode := not ListView1.EditMode;
end;
procedure TFormMain.ListView1DeletingItem(Sender: TObject; AIndex: Integer;
var ACanDelete: Boolean);
begin
// Permet d'annuler la suppression (par exemple après confirmation)
ACanDelete := True;
end;2. Ajouter un bouton personnalisé via une apparence dynamique. Pour un bouton « Supprimer » toujours visible à droite de la ligne, on utilise une apparence comme ListItemRightDetail enrichie d'un TListItemTextButton ajouté au runtime. Important : TListItemTextButton est un drawable enfant de l'item — on l'instancie via son constructeur en lui passant l'item comme parent, on ne fait jamais un simple DeleteButton.Text := … sur une variable non initialisée.
uses
FMX.ListView.Appearances;
procedure TFormMain.AjouterBoutonSupprimerAItem(Item: TListViewItem;
TagID: Integer);
var
Btn: TListItemTextButton;
begin
// Le bouton se rattache aux Objects de l'item via son constructeur
Btn := TListItemTextButton.Create(Item);
Btn.Name := 'btnDelete';
Btn.Text := 'Supprimer';
// Énumération imbriquée — pas TListItemButtonType !
Btn.ButtonType := TListItemTextButton.TButtonType.Delete;
Btn.TagString := TagID.ToString;
Btn.PlaceOffset.X := -10;
Btn.Align := TListItemAlign.Trailing;
Btn.TextAlign := TTextAlign.Trailing;
end;
procedure TFormMain.ListView1ItemClickEx(const Sender: TObject;
ItemIndex: Integer; const LocalClickPos: TPointF;
const ItemObject: TListItemDrawable);
begin
// Détecter le clic sur le bouton personnalisé
if (ItemObject <> nil) and (ItemObject.Name = 'btnDelete') then
SupprimerElementParTag(ItemObject.TagString);
end;💡 La signature de l'événement de clic « étendu » est bien
OnItemClickEx, pasOnClicksur le bouton lui-même :TListItemDrawablen'expose pas d'événementOnClickpropre.
Excellent pour organiser différentes sections de votre application.
// Créer une navigation par onglets
procedure TFormMain.CreerOnglets;
var
TabItem1, TabItem2: TTabItem;
begin
TabControl1.Align := TAlignLayout.Client;
// Premier onglet
TabItem1 := TTabItem.Create(TabControl1);
TabItem1.Parent := TabControl1;
TabItem1.Text := 'Accueil';
// Deuxième onglet
TabItem2 := TTabItem.Create(TabControl1);
TabItem2.Parent := TabControl1;
TabItem2.Text := 'Paramètres';
end;Sur un petit écran, l'espace est précieux. Établissez une hiérarchie claire avec :
- Des titres plus grands et en gras
- Des espacements généreux entre les sections
- Des groupements logiques d'informations
Sur mobile, les utilisateurs tiennent souvent leur téléphone d'une main et interagissent avec le pouce. Les zones faciles à atteindre se situent :
- Facile : Bas et milieu de l'écran
- Difficile : Haut et coins opposés
Placez les actions principales dans les zones faciles d'accès.
// Placer un bouton d'action principal en bas
procedure TFormMain.PlacerBoutonPrincipal;
begin
BoutonPrincipal.Align := TAlignLayout.Bottom;
BoutonPrincipal.Height := 60;
BoutonPrincipal.Margins.Rect := RectF(10, 10, 10, 10);
end;Les écrans mobiles sont souvent utilisés en extérieur avec beaucoup de lumière. Assurez-vous d'avoir :
- Un contraste élevé entre le texte et le fond
- Une taille de police suffisante (minimum 14-16 points pour le corps de texte)
- Des couleurs distinctes pour les éléments interactifs
// Configurer un style avec bon contraste
procedure TFormMain.ConfigurerStyle;
begin
Label1.TextSettings.Font.Size := 16;
Label1.TextSettings.FontColor := TAlphaColors.Black;
Label1.Fill.Color := TAlphaColors.White;
end;Ne surchargez pas l'écran. Chaque écran devrait avoir :
- Un objectif principal clair
- Peu d'options (5-7 maximum)
- Des espaces blancs pour respirer
Les animations rendent l'interface plus fluide et aident l'utilisateur à comprendre les changements d'état.
uses
FMX.Ani;
// Faire glisser un nouvel écran depuis la droite
procedure TFormMain.AnimerTransition;
begin
// Positionner le nouvel écran hors de vue à droite
NouvelEcran.Position.X := ClientWidth;
NouvelEcran.Visible := True;
// Animer le glissement
TAnimator.AnimateFloat(NouvelEcran, 'Position.X', 0, 0.3,
TAnimationType.In, TInterpolationType.Cubic);
end;// Créer un effet "rebond" lors du clic
procedure TFormMain.AnimerBoutonClic(Sender: TObject);
begin
// Réduire légèrement
TAnimator.AnimateFloat(Sender, 'Scale.X', 0.95, 0.1);
TAnimator.AnimateFloat(Sender, 'Scale.Y', 0.95, 0.1);
// Puis revenir à la normale
TAnimator.AnimateFloatDelay(Sender, 'Scale.X', 1.0, 0.1, 0.1);
TAnimator.AnimateFloatDelay(Sender, 'Scale.Y', 1.0, 0.1, 0.1);
end;// Animer un changement de couleur pour indiquer une action
procedure TFormMain.AnimerFeedback;
begin
Rectangle1.Fill.Color := TAlphaColors.Green;
// Revenir à la couleur normale après 0.5 secondes
TAnimator.AnimateColorDelay(Rectangle1, 'Fill.Color',
TAlphaColors.Lightgray, 0.3, 0.5);
end;Sur mobile, le clavier occupe une grande partie de l'écran lorsqu'il apparaît.
L'événement OnVirtualKeyboardShown est déclenché à chaque apparition/disparition du clavier virtuel. Bounds donne le rectangle (en pixels écran) occupé par le clavier — il faut convertir Bounds.Top en coordonnées formulaire avec ScreenToClient pour calculer la hauteur disponible restante :
procedure TFormMain.FormVirtualKeyboardShown(Sender: TObject;
KeyboardVisible: Boolean; const Bounds: TRect);
var
ClientTopDuClavier: Single;
begin
if KeyboardVisible then
begin
// Bounds est en coordonnées écran ; on le ramène au formulaire
ClientTopDuClavier := ScreenToClient(PointF(Bounds.Left, Bounds.Top)).Y;
// La zone de contenu s'arrête juste au-dessus du clavier
ScrollBox1.Height := ClientTopDuClavier - ScrollBox1.Position.Y;
end
else
begin
// Le clavier disparaît : on rétablit la hauteur initiale
ScrollBox1.Height := ClientHeight - ScrollBox1.Position.Y;
end;
end;💡 Si vous avez un
TVertScrollBoxalignéClient, FMX gère partiellement ce décalage tout seul (le champ qui a le focus reste visible). N'intervenez à la main que pour les mises en page non triviales.
Utilisez le bon type de clavier selon le contenu attendu :
// Configurer le type de clavier pour chaque champ
procedure TFormMain.ConfigurerClaviers;
begin
// Clavier numérique pour les nombres
EditAge.KeyboardType := TVirtualKeyboardType.NumberPad;
// Clavier email pour les adresses email
EditEmail.KeyboardType := TVirtualKeyboardType.EmailAddress;
// Clavier téléphone
EditTelephone.KeyboardType := TVirtualKeyboardType.PhonePad;
// Clavier URL
EditSiteWeb.KeyboardType := TVirtualKeyboardType.URL;
end;// Configurer les actions de retour du clavier
procedure TFormMain.ConfigurerRetourClavier;
begin
// "Suivant" pour passer au champ suivant
EditNom.ReturnKeyType := TReturnKeyType.Next;
EditNom.OnKeyDown := PasserChampSuivant;
// "Terminé" pour le dernier champ
EditEmail.ReturnKeyType := TReturnKeyType.Done;
EditEmail.OnKeyDown := FermerClavier;
end;
procedure TFormMain.PasserChampSuivant(Sender: TObject; var Key: Word;
var KeyChar: Char; Shift: TShiftState);
begin
if Key = vkReturn then
begin
EditPrenom.SetFocus;
Key := 0; // Consommer l'événement
end;
end;Créer une interface utilisateur tactile efficace demande de repenser complètement votre approche de conception par rapport aux applications desktop traditionnelles. Les principes clés à retenir sont :
- Taille des cibles : Minimum 44x44 points pour tous les éléments interactifs
- Espacement : Laisser suffisamment d'espace entre les contrôles
- Feedback visuel : Toujours indiquer clairement les interactions
- Gestes naturels : Supporter tap, swipe, pinch selon le contexte
- Adaptation : Votre interface doit s'adapter à toutes les tailles et orientations
- Simplicité : Privilégier la clarté et le minimalisme
- Performance : Des animations fluides à 60 FPS
FireMonkey offre tous les outils nécessaires pour créer des interfaces tactiles modernes et réactives. En appliquant ces principes et en testant régulièrement sur de vrais appareils, vous créerez des applications mobiles agréables et intuitives à utiliser.
Dans la section suivante, nous verrons comment exploiter les capteurs des appareils mobiles pour créer des expériences encore plus riches et interactives.