在 Flutter 中构建设计系统

在 Flutter 中实现可扩展和固执己见的设计系统的技巧和窍门



Nielson Normal Group(一家用户体验研究咨询公司)将设计系统定义如下:


设计系统是一套标准,通过减少冗余来大规模管理设计,同时在不同页面和渠道之间创建共享语言和视觉一致性。”


与名称可能暗示的不同,设计系统的规则不仅仅适用于设计师。一个精心构建和实施的设计系统的真正价值在于将这些规则强加给设计师和开发人员,创造一致性,使两个学科能够专注于更高层次的挑战,而忽略构成一个有凝聚力的应用程序的单调乏味的组成部分。


您可能听说过Bootstrap和antd for web 等设计系统,或者可能听说过 AirBnB 的设计语言系统。即使他们不在屋顶上大声疾呼,在设计方面取得成功的公司也可能拥有设计系统。这使他们能够专注于其应用程序的标识和功能,而不必考虑按钮、横幅、文本等个别部分。


作为一名设计师,我不想在开始设计页面时就必须考虑按钮是什么,并详尽地创建供开发人员使用的规范。作为一名开发人员,我不希望收到设计并看到我必须第十次从头开始构建的按钮。一个好的设计系统及其实现的对应物(在我们的例子中是一个 Flutter 库)解决了这些问题。


我们将跳过讨论设计系统是如何形成的,谁制定了标准,以及它是如何记录的。相反,我们假设我们有一个定义明确的设计系统并将其称为MyDesign. 我们的工作是MyDesign在 Flutter 中构建组件,并让它们准确地代表我们的设计系统定义的标准。我们将特别关注一组按钮小部件:



一个过于简单的设计系统

本文接下来的内容是我学到的提示和技巧,这些提示和技巧导致了成功的、可扩展的和可重用的设计系统实现。


命名很重要

作为开发人员,我们知道语义对于采用和入职非常重要。但就设计系统而言,这延伸到了我们友好的社区设计师。我们正在创建一种共享语言,因此应该使用该语言来实现我们的小部件。


在描述组件时,尽量使用与设计人员相同的名称。这确保了在设计和实施之间来回工作时不会出现沟通错误。将此方法也应用于您的小部件的配置。如果一个按钮有一个“leading”和“trailing”图标而不是“left”和“right”,那么在你的widget类的字段中使用相同的术语。在MyDesign按钮的情况下,我们可以看到它们反映了材料填充(提升)和轮廓按钮,但被命名为主要和次要。我们的实施应该尊重该命名方案。


设计系统实现通常独立于它们支持的应用程序。这是一种有益的解耦,因此业务逻辑不会渗透到设计实现中,并且您的库可以作为依赖项跨多个消费应用程序重复使用。因此,我发现设计系统提供的小部件前缀也是有益的。MyButtoninstead ofButton有助于区分应用程序中哪些小部件是本地的,哪些不是本地的,并避免与 Flutter 和其他应用程序依赖项提供的许多小部件发生名称冲突。


独立定义设计令牌

设计令牌是设计系统的“原语”——在整个组件和定义的标准中重复使用的常量值。颜色、间距、文本样式和图标之类的东西通常作为“标记”包含在设计系统中,并且是独立于使用它们的小部件进行定义的良好候选者。Material Design 已经使用Colors和Icons类以及包含预定义文本处理(如正文和标题样式textTheme)的默认对象来实现这一点。Theme



定义一组颜色标记

使用组合

Flutter 建立在积极的可组合性之上,您的设计系统库也应该如此。利用 Flutter 广泛的 Material Design 和 Cupertino 小部件目录,并根据您的系统规格设置它们的样式。这从您的小部件将被使用的所有地方抽象出样式。通过创建可以组合到其他小部件中的较小小部件,避免跨小部件重复代码。使用MyDesign按钮,我们将组成 Material 的按钮作为基础。在更复杂的系统中,您可能拥有自己的基础组件,这些组件可以组合成多个其他组件。


减少 API 面

尝试使您的小部件尽可能简单。遵循最少知识原则——一个小部件应该只使用它正确显示和运行所需的输入。这也意味着您的小部件不能以意想不到的方式使用。


如果您正在使用 Material 小部件并为您的设计设置样式,您可能不需要小部件允许的所有配置。Material 小部件旨在高度可配置,但您的小部件可能不是。减少那些参数!


一些像这样的小部件ElevatedButton在可以作为孩子传递的东西方面非常灵活(它需要任何Widget)。在MyDesign中,按钮只允许文本和图标作为子项,因此我们将重新键入小部件的字段以确保只接受有效值,并允许构建函数抽象出构建按钮内部结构的复杂性。



MyDesign 按钮的初步实现

使用枚举强制执行有效输入

此提示是对上述建议的扩展。在许多情况下,小部件的字段类型可以允许不符合您的设计系统规则的值。例如,MyDesign的按钮只允许使用品牌调色板中的一部分颜色。我们不会让我们的小部件采用Color类型参数(因此允许颜色不正确的按钮),我们将创建一个枚举来表示并将配置限制为允许的配置。


在 Dart 2.17 的增强型枚举Map之前,这会导致一些小烦恼,即必须使用or switch case将这些枚举值映射回我们的构造函数或构建函数中的有效类型。然而,通过增强的枚举,我们可以定义带有 final 字段的枚举,将每个枚举值连接到它的表示值。



现在我们的按钮遵循 MyDesign 的颜色规则

继承样式

不对值进行硬编码总是一个好主意。我们主要通过将设计标记分离成常量来解决这个问题。然而,在我们的代码中使用MyColors.blueinplace ofColor(0xff0000ff)仍然会给我们的设计系统带来不必要的限制。如果设计系统需要更改,我们的令牌允许在一个单独的地方编辑值,但如果我们需要一个全新的主题怎么办?这是应用程序中浅色和深色主题的常见做法。


静态常量变量无法解决用户对主题的偏好。因此,像 Material design 一样,通过修改属性来使用全局样式的继承Theme,它带有或通过创建主题扩展。


使用命名构造函数

这可能归结为个人偏好,但 dart 的命名构造函数可以帮助减少样板并增强小部件的语义。


查看我们的MyDesign主要和次要按钮,我们知道在构建内部结构时有重用代码,但我们仍然需要分别使用 MaterialElevatedButton和OutlineButton。我们可以创建两个单独的小部件MyPrimaryButton,MySecondaryButton并提取一个小部件来构建子项。或者,我们可以有一个带有命名构造函数的小部件,MyButton.primary并且MyButton.secondary.


这些构造函数可以设置一个私有字段,告诉我们在构建方法中要做什么。随着逻辑和构建方法的复杂性增加(代码共享比协调多个小部件通信更容易),这种方法在多个小部件上变得更有价值。出于语义目的,以这种方式“分组”小部件的变体也很有价值。通过 IDE 代码完成,键入MyButton.会提供可用变体的“目录”,这是通过多小部件方法无法获得的好处。



使用命名构造函数对变体小部件进行分组

结论

您可以随心所欲地严格设计系统。在许多情况下,相信开发人员遵守口头或书面规则就足够了。但是,构建利用与设计人员共享的术语并严格执行系统规则的小部件可以加快从设计到开发的交接,并使未来的开发人员更容易上手。


首页 > 新闻资讯

Tag: UI外包公司 深圳UED设计公司 北京UI设计公司 用户体验设计咨询公司
留言