上一篇 介绍了 UI
设计系统实现中的原子级别如 color
、font
、padding
、radius
等的管理方式,本篇主要来介绍设计系统中分子级别和细胞级别,也就是一些最基本和常见的 widget
及自定义的 widget
,来看看在 UI
设计系统是如何对它们进行封装的。
我们在写 UI
界面的时候,经常会遇到很多 widget
它们长得很像,却又有一些细微的差别,比如说在很多页面都会出现的操作 button
,有提交表单数据 primary button
,也有其它交互的操作的 secondary button
等等,但是这些按钮之间只有背景颜色、显示文案及用户点击的回调的区别。
这个时候应该怎么做呢?先来说一说前三种做法,第一种在页面上每一个用到按钮的位置直接使用,第二种就是为每种按钮类型创建一个小的 Widget
1 | dart复制代码// 第一种做法 |
第三种就是在第二种的基础上将抽取一个父类,将相同属性和操作放在父类,不同的放在子类,但是不太推荐这么做,至少是在这种情况下不推荐,本来就是一个简单的 widget
的封装,搞个父类会让 widget
的维护变复杂了。而第一种和第二种做法也可以,但在整个项目中会有大量重复代码,代码重用性不好,有没有更好的做法呢?这里使用的是 widget
工厂。
widget
工厂
这里同样以文案居中的 button
为例,下面来创建一个类名为 CenteredTextButton
的自定义button
组件,它包含了两个工厂方法:primary
和 secondary
,分别用于创建两个不同样式的按钮。每个工厂方法内部通过调用 CenteredTextButton._internal
构造函数来创建按钮实例,并根据传入的参数设置按钮的样式和行为。
1 | dart复制代码class CenteredTextButton extends StatelessWidget { |
这里是的颜色和文本样式的定义放在了是上一篇介绍的 AppColorsTheme
和 AppTextsTheme
。使用的定制性更高的 InkWell
来作为响应用户点击的容器组件,NoSplash.splashFactory
去掉点击时的水波纹效果。在页面中使用:
1 | dart复制代码Column( |
每个工厂中仅添加必要的参数,使得代码更简单并避免代码重复,那这样实现有什么好处呢?将每个工厂中的通用属性分组,不必每次在应用程序中需要相同的小 widget
时重复这些通用属性,管理起来也方便统一。而且这样写也很方便拓展更多的小 widget
,只需要添加一个新工厂就可以轻松添加新的小部件,如:CenteredTextButton.tertiary
也可以有自己的特定参数值。
除了上面的 button
,还有没有其它的 widget
也可以这么设计呢?当然有,而且很多,比如文本、文本输入和图片等等,甚至 widget
之间的间隙(gap
),都可以使用上述做法来设计。
文本显示:
AppText.labelLargeEmphasis(...)
AppText.labelDefaultEmphasis(...)
文本输入:
AppTextField.text()
AppTextField.search()
AppTextField.number()
AppTextField.email()
AppTextField.password()
你可能会问 widget
之间的间隙不是可以通过 padding
、margin
来实现吗,还需要单独重新设计一系列的 gap
?我自己的经验是,所有的 widget
之间的间隙尽量是可见的,意思就是单独把间隙用 SizedBox
来表示,尽量避免子小部件内隐藏的间隙和间距,除非是特殊情况必须得这么做。下面代码实现封装的各种 gap
。
1 | dart复制代码import 'package:flutter/material.dart'; |
widget
组合
这个就很好理解了,就是将多个基础 widget
组合成一个复合 widget
,从而实现更复杂的功能或UI布,这里的参与组合的 widget
既有系统的也有上面内容里自定义的 widget
,所以组合的 widget
在设计系统中可以属于分子级别也可以是细胞级别。下面来实现一个自定义 AppBar
的例子 :
1 | dart复制代码import 'package:flutter/material.dart'; |
上面代码中的 AppBarButton
就是我们自己的封装的 widget
,CustomAppBar
组件内部使用了 AppBar
和一些内置的 Widget
(如 Text
)还有我们自定义的,来实现的布局和样式。这种 widget
的组合封装小到一个 AppBar
,有些情况下也可以大到一个页面。好处就是在应用中重复使用这个自定义的组合 widget
,而不需要重复编写相似的代码,提高了代码的复用性和可维护性。
widget
自定义绘制
自定义绘制是属于设计系统中细胞级别的,项目中我们常使用 CustomPainter
来做自定义绘制,因为有的时候 Flutter
内置组件无法满足特定设计需求,亦或者在需要绘制复杂图形、图表及各种特殊的效果、动画等场景下,同时自定义绘制可以实现更高效的渲染,尤其是绘制大量图形或动画时,可以减少 Flutter
框架的开销,提高性能。下面用 CustomPainter
绘制一个不规则形状的按钮。
1 | dart复制代码class IrregularButton extends StatelessWidget { |
在项目架构中的位置
从上面的架构图可以看出,上面介绍的通过工厂、组合和自定义绘制的widget
(分子级别和细胞级别)是放在了 widgets
组件包内的,widgets
组件内部会依赖于 resources
组件和 shared
组件。在主工程中添加对 widgets
的依赖就可以直接使用。
1 | yaml复制代码dependencies: |
下图是 widgets
组件内部的文件结构:
小结
UI
设计系统除了在代码层的实现,还需要 UI
设计师定义一套 UI
组件的设计规范和风格来做配合,以确保界面的一致性和美观性。本文上面和上一篇介绍的 widget
封装方法只是提供一种参考。好了,今天的分享就到这里,《Flutter大型项目架构》 系列已经更新到第五篇,本系列的下一篇来介绍大型项目中网络层是如何设计和实现的,感谢您的阅读,记得关注加点赞哦!
本文转载自: 掘金