Trucs et astuces pour mettre en œuvre un système de conception évolutif et avisé dans Flutter
Nielson Normal Group (un cabinet de conseil en recherche UX) définit un système de conception comme suit :
« Un système de conception est un ensemble de normes permettant de gérer la conception à grande échelle en réduisant la redondance tout en créant un langage partagé et une cohérence visuelle sur différentes pages et canaux. »
Contrairement à son nom, les règles des systèmes de conception ne s’appliquent pas uniquement aux concepteurs. La valeur réelle d’un système de conception bien construit et mis en œuvre consiste à imposer ces règles aux concepteurs et aux développeurs, créant une cohérence qui permet aux deux disciplines de se concentrer sur des défis de niveau supérieur et d’ignorer l’ennui des pièces de composition qui forment une application cohérente.
Vous avez peut-être entendu parler de systèmes de conception comme Amorcer et et pour le Web, ou peut-être AirBnB Système de langage de conception. Même si elles ne le crient pas sur tous les toits, les entreprises qui réussissent dans la conception ont probablement un système de conception. Cela leur permet de se concentrer sur l’identité et la fonctionnalité de leurs applications sans avoir à penser à des éléments individuels tels que des boutons, des bannières, du texte, etc.
En tant que designer, je ne veux pas commencer à concevoir une page et devoir réfléchir à ce qu’est un bouton et créer de manière exhaustive des spécifications pour la consommation des développeurs. En tant que développeur, je ne veux pas recevoir un design et voir un bouton que je dois construire à partir de zéro pour la dixième fois. Un bon système de conception et son homologue implémenté (dans notre cas, une bibliothèque Flutter) résolvent ces problèmes.
Nous ne discuterons pas de la manière dont un système de conception est né, de qui établit les normes et de la manière dont il est documenté. Au lieu de cela, nous supposerons que nous avons un système de conception bien défini et l’appellerons MyDesign
. Notre travail consiste à construire les composants de MyDesign
dans Flutter et faites en sorte qu’ils représentent avec précision les normes définies par notre système de conception. Nous nous concentrerons spécifiquement sur un ensemble de widgets de boutons :
Ce qui suit dans cet article sont des trucs et astuces que j’ai appris et qui ont conduit à des implémentations de systèmes de conception réussies, évolutives et réutilisables.
En tant que développeurs, nous savons que la sémantique est extrêmement importante pour l’adoption et l’intégration. Mais dans le cas des systèmes de conception, cela s’étend à nos sympathiques concepteurs de quartier. Nous créons un langage partagé et devrions donc implémenter nos widgets en utilisant ce langage.
Efforcez-vous d’utiliser les mêmes noms pour vos widgets que les concepteurs lorsqu’ils décrivent les composants. Cela garantit qu’il n’y a pas de problèmes de communication lors des allers-retours entre la conception et la mise en œuvre. Appliquez également cette méthodologie à la configuration de vos widgets. Si un bouton a une icône « avant » et « arrière » au lieu de « gauche » et « droite », utilisez la même terminologie dans les champs de votre classe de widget. Dans le cas de MyDesign
boutons, nous pouvons voir qu’ils reflètent les boutons remplis de matériau (élevés) et soulignés, mais sont nommés primaires et secondaires. Notre implémentation doit respecter ce schéma de nommage.
Les implémentations de systèmes de conception vivent souvent indépendamment des applications qu’elles prennent en charge. Il s’agit d’un découplage bénéfique pour que la logique métier ne se répercute pas sur l’implémentation de la conception et que votre bibliothèque puisse être réutilisée en tant que dépendance entre plusieurs applications consommatrices. J’ai trouvé qu’à cause de cela, un préfixe pour les widgets fourni par le système de conception est également bénéfique. MyButton
à la place de Button
aide à distinguer les widgets d’une application qui sont locaux et ceux qui ne le sont pas, ainsi qu’à éviter les conflits de noms avec les nombreux widgets fournis par Flutter et d’autres dépendances d’applications.
Les jetons de conception sont les « primitives » d’un système de conception – des valeurs constantes réutilisées dans les composants et les normes définies. Des éléments tels que les couleurs, les espacements, les styles de texte et les icônes sont souvent inclus dans les systèmes de conception en tant que « jetons » et sont de bons candidats à définir indépendamment des widgets qui les utilisent. La conception matérielle le fait déjà avec le Colors
et Icons
cours, ainsi que les textTheme
du défaut Theme
objet contenant des traitements de texte prédéfinis comme les styles de corps et de titre.
Flutter est construit sur composabilité agressive, et votre bibliothèque de système de conception devrait l’être aussi. Utilisez le vaste catalogue de widgets Material Design et Cupertino de Flutter et personnalisez-les en fonction des spécifications de votre système. Cela supprime le style de tous les endroits où vos widgets seront utilisés. Évitez de répéter le code entre les widgets en créant des widgets plus petits que vous pouvez composer dans d’autres. Avec MyDesign
boutons, nous composerons les boutons de Material comme base. Dans des systèmes plus complexes, vous pouvez avoir vos propres composants de base, qui peuvent être composés en plusieurs autres.
Essayez de rendre vos widgets aussi simples que possible. Abonnez-vous à la principe de moindre connaissance — un widget ne doit consommer exactement que les entrées dont il a besoin pour s’afficher et fonctionner correctement. Cela signifie également que votre widget ne peut pas être utilisé de manière inattendue.
Si vous utilisez un widget Material et que vous le stylisez pour votre conception, vous n’avez probablement pas besoin de toutes les configurations autorisées par le widget. Les widgets matériels sont destinés à être hautement configurables, mais vos widgets peuvent ne pas l’être. Réduisez ces paramètres !
Certains widgets comme ElevatedButton
sont extrêmement flexibles dans ce qui peut être transmis pendant l’enfance (il faut tout Widget
). Dans MyDesign
les boutons n’autorisant que le texte et les icônes en tant qu’enfants, nous allons donc retaper les champs de notre widget pour nous assurer que seules les valeurs valides sont acceptées et permettre à la fonction de construction d’abstraire les complexités de la construction des composants internes du bouton.
Cette astuce est une extension de la recommandation ci-dessus. Dans de nombreux cas, les types de champ d’un widget peuvent autoriser des valeurs qui ne correspondent pas aux règles de votre système de conception. Par exemple, MyDesign
Les boutons de n’autorisent qu’un sous-ensemble de couleurs de la palette de la marque. Plutôt que d’avoir notre widget prendre unColor
paramètre de type (et donc autorisant les boutons de couleur incorrecte), nous allons créer une énumération qui représente et limite la configuration à ceux qui sont autorisés.
Avant Dart 2.17 énumérations amélioréescela causerait le désagrément mineur d’avoir à mapper ces valeurs d’énumération à un type valide dans notre constructeur ou fonction de construction à l’aide d’un Map
ou changer de boîtier. Cependant, avec les énumérations améliorées, nous pouvons définir des énumérations avec des champs finaux reliant chaque valeur d’énumération à sa valeur représentée.
C’est toujours une bonne idée de ne pas coder les valeurs en dur. Nous nous sommes principalement occupés de cela en séparant les jetons de conception en constantes. Cependant, en utilisant MyColors.blue
au lieu de Color(0xff0000ff)
tout au long de notre code peut encore contraindre inutilement notre système de conception. Alors que nos jetons permettent à un endroit unique de modifier les valeurs si le système de conception a besoin de modifications, que se passe-t-il si nous avons besoin d’un thème entièrement nouveau ? C’est une pratique courante avec les thèmes clairs et sombres dans les applications.
Les variables constantes statiques ne peuvent pas résoudre la préférence de l’utilisateur dans le thème. Ainsi, comme la conception de matériaux, utilisez l’héritage des styles du global Theme
en modifiant les propriétés, il vient avec ou en créant extensions de thème.
Cela peut dépendre d’une préférence personnelle, mais les fléchettes constructeurs nommés peut aider à réduire le passe-partout et à améliorer la sémantique de vos widgets.
En regardant notre MyDesign
boutons primaires et secondaires, nous savons qu’il y a du code réutilisé dans la construction des composants internes, mais nous aurons toujours besoin d’un matériau ElevatedButton
et OutlineButton
respectivement. Nous pourrions créer deux widgets distincts MyPrimaryButton
et MySecondaryButton
et extraire un widget pour construire les enfants. Alternativement, nous pourrions avoir un seul widget avec des constructeurs nommés, MyButton.primary
et MyButton.secondary
.
Ces constructeurs peuvent définir un champ privé qui nous dit quoi faire dans notre méthode de construction. Cette approche devient plus précieuse sur plusieurs widgets à mesure que la logique et la méthode de construction augmentent la complexité (le partage de code est plus facile que la coordination de la communication de plusieurs widgets). Il peut également être utile de « regrouper » des variantes de widgets de cette manière à des fins sémantiques. Avec l’achèvement du code IDE, en tapant MyButton.
donne un « catalogue » des variantes disponibles, un avantage non reçu par une approche multi-widget.
Vous pouvez être aussi strict avec votre système de conception que vous le souhaitez. Faire confiance aux développeurs pour qu’ils adhèrent aux règles orales ou écrites peut suffire dans de nombreuses circonstances. Mais créer des widgets qui tirent parti de la terminologie partagée avec les concepteurs et appliquent strictement les règles du système peut conduire à un transfert plus rapide de la conception au développement et à une intégration plus facile pour les futurs développeurs.