中英文模式阅读
中文模式阅读
英文模式阅读

How to build design system with SwiftUI

Building a design system to support one product is not easy - it has to be robust and flexible at the same time for scalability. Though challenging,
构建支持一种产品的设计系统并不容易 - 它必须具有强大和灵活性,同时具有可扩展性。虽然挑战,lots
of
great
resources have shared useful principles and approaches that help teams build a good system both visually and programmatically. Standing on their shoulders, this article tries to contribute to an untouched ground by focusing on building a good system in
共享有用的原则和方法,帮助团队在视觉和程序上建立一个良好的系统。站在他们的肩膀上,本文试图通过专注于建立一个良好的系统来促进未受破坏的基础SwiftUI.

Why do I write this article {#why-do-i-write-this-article}

During my first summer in
在我的第一个夏天ITP at New York, I'm lucky to have the opportunity to work as an iOS developer intern at
在纽约,我很幸运有机会成为iOS开发人员Line Break Studio. One task I've been assigned to is building a design system in two steps: first visually in
。我被分配的一项任务是分两步建立一个设计系统:首先是视觉上的Sketch, and then programmatically in
,然后以编程方式进入SwiftUI. The experience of experimenting with the new framework and building a design system with it has been amazing, but also buggy along the way. That's why we'd like to share our experience with the community, hopefully making your development process easier.
。尝试使用新框架并使用它构建设计系统的经验令人惊叹,但同时也有错误。这就是为什么我们想与社区分享我们的经验,希望让您的开发过程更轻松。


What is SwiftUI {#what-is-swiftui}

Apple released this groundbreaking new framework in
Apple发布了这个开创性的新框架WWDC 2019, which is one of the bests in years. From the point of view as a web developer, the project development experience in
,这是多年来的最佳成果之一。从作为Web开发人员的角度来看,项目开发经验SwiftUI is closer to which in conventional front-end stack and frameworks.
在传统的前端堆栈和框架中更接近于它。

This is definitely an awesome move because programming interface and managing states are drastically easier than before. And the best part of this improvement is that one can
这绝对是一个非常棒的举动,因为编程接口和管理状态比以前更容易。这种改进的最好部分是人们可以integrate UIKit and SwiftUI smoothly. To learn the basics of SwiftUI, the
。要学习SwiftUI的基础知识official tutorials provided by Apple are very helpful. Intro to SwiftUI from WWDC
由Apple提供的非常有帮助。从WWDC介绍SwiftUI

The demo project {#the-demo-project}

For demonstration purpose, I put up a simplified version of design system we built in
为了演示目的,我提出了我们内置的设计系统的简化版本Line Break Studio. It a set of
。它是一套 button components in different forms, which are built on top of two lower level parts:
不同形式的组件,构建在两个较低级别的部件之上: typography and
colorPalette .
Dynamic rendering view of the demo project
演示项目的动态渲染视图

The project is
该项目是public on GitHub, and I'm using
,我正在使用Xcode 11 Beta 5 for development. An
发展。一个Airtable base as design system management hub (read
作为设计系统管理中心(阅读more about workflow management) is also public for reference.
)也是公开的参考。


Principles of building design system {#principles-of-building-design-system}

Design system in code is a middleware between designers and developers. Developer of the system takes inputs from design system in visual form, and produces API that's identical with which for further development. Following two principles should be recognized to complete this system in code:
代码中的设计系统是设计人员和开发人员之间的中间件。系统开发人员以视觉形式从设计系统中获取输入,并生成与进一步开发相同的API。应该承认以下两个原则在代码中完成此系统:

1. Communicate with tokens {#1-communicate-with-tokens}

Fundamentally, the purpose of having a design system in program is not about better code management or development efficiency, but to make sure the
从根本上说,在程序中使用设计系统的目的不是为了更好的代码管理或开发效率,而是为了确保 view is consistent with design files. To achieve that goal, using tokens to signify certain color, font, size or any visual elements is crucial to maintain quality of communication between developers, designers and managers in a team.
与设计文件一致。为了实现这一目标,使用令牌来表示某些颜色,字体,大小或任何可视元素对于保持团队中开发人员,设计人员和管理人员之间的沟通质量至关重要。
Lightning Design System's tokens built by Salesforce
由Salesforce构建的令牌

2. Levels of hierarchy {#2-levels-of-hierarchy}

In
EightShapes' article, it points out that we should "Show options first, then decisions next", because "You can't make decisions without options."
,它指出我们应该"首先显示选项,然后再显示决策",因为"没有选项,你就无法做出决定"。
EightShapes' article about design tokens
关于设计代币

This kind of ordering architecture loosens the degree of coupling between different levels, hence providing more flexibility and dynamic for possible revisions. The way I structure the levels is in this order from bottom to top: material → base → token. But it could be anyway the team's comfortable with.
这种排序架构放松了不同级别之间的耦合程度,因此为可能的修订提供了更大的灵活性和动态性。我构建关卡的方式从下到上依次为:material→base→token。但无论如何,这可能是团队感到满意的。


Diving into code {#diving-into-code}

Following section is a list of highlights we'd like to point out based on our experience. Please
以下部分是根据我们的经验我们想要指出的重点列表。请visit the GitHub repo for complete code. Any feedbacks or critics are welcome for improvements.
完整的代码。欢迎任何反馈或评论家进行改进。

1. Architecting levels of hierarchy {#1-architecting-levels-of-hierarchy}

There're two ways of stacking materials at lower level to construct tokens at highest level:
在较低级别堆叠材料有两种方法可以在最高级别构建令牌:

  • Use enum for type safety and code literacy

Advantages of using enum in code as grouping wrapper or parameter in function have already been well recognized. One point worths mentioning here is the implementation of levels of hierarchy.
在代码中使用枚举作为分组包装器或函数中的参数的优点已经得到了很好的认识。值得一提的一点是层次结构的实现。

We always store the raw values, including font size (
我们总是存储原始值,包括字体大小(CGFloat) and font name (
)和字体名称(String), at the lowest level, because we don't want to mess around with it. But because raw value must be a literal in enum, we can't just assign a
),在最低层,因为我们不想乱用它。但是因为原始值必须是枚举中的文字,所以我们不能只指定一个case to be a value from the other enum.
是另一个枚举的值。

To work around this problem, we implement a function
为了解决这个问题,我们实现了一个函数getValue, which returns the raw value in
,返回原始值switch case when necessary.
必要时的情况。

  • Use struct for easier structure

Though enum is great, we don't need its unique feature in some cases. For example, because
虽然枚举很棒,但在某些情况下我们不需要它的独特功能。例如,因为Xcode takes care of the heavy job of processing dynamic colors, and no parameter options are required in API endpoint, we can set up color palettes by simple two levels of struct.
处理动态颜色的繁重工作,API端点不需要参数选项,我们可以通过简单的两级结构设置调色板。

2. Clear and straightforward naming of API endpoint {#2-clear-and-straightforward-naming-of-api-endpoint}

Naming convention is another broad topic for discussion and debate. In addition to basic
命名惯例是讨论和辩论的另一个广泛主题。除了基本的Swift conventions, the only two rules we abide are, 1) no acronym and 2) making it simple. For example, to use typography and color system, instead of creating new endpoints, we make extension from Font and Color structs. This approach decreases the effort to memorize unfamiliar API names for developers.
,我们遵守的唯一两条规则是:1)没有首字母缩略词,2)简单易懂。例如,要使用排版和颜色系统,而不是创建新的端点,我们从字体和颜色结构进行扩展。这种方法减少了为开发人员记忆不熟悉的API名称的工作量。

3. Manage color sets dynamically in two modes {#3-manage-color-sets-dynamically-in-two-modes}

So dark mode has become a standard in industry, and both
所以黑暗模式已成为行业的标准,两者兼而有之iOS and
Android team have implemented this feature. It's a good trend for users, but could bring designers and developers some challenges, including managing and naming the color sets, especially gray scale ones.
团队已实施此功能。这对用户来说是一个很好的趋势,但可能会给设计人员和开发人员带来一些挑战,包括管理和命名颜色集,尤其是灰度集。
Material Design's dark theme guide
黑暗的主题指南

To think and communicate about gray scale colors dynamically, using terms like
使用类似术语动态思考和交流灰度颜色 white ,
light ,
black or
要么 dark doesn't work. Because if we referred to a dynamic color
不起作用。因为如果我们提到动态的颜色#000000 (black in HEX)
(HEX黑色) black or
要么 dark in
light color scheme, how do you talk about this particular color, which should turn into
,你怎么谈这个应该变成的特殊颜色#FFFFFF (white in HEX), in
(HEX中的白色),indark color scheme?
defaultDark or
要么 lightDark ?
Confusing transition of color sets
令人困惑的颜色集转换

It is very confusing to name gray scale dynamic color sets in conventional approach. To avoid this confusion, we use
在传统方法中命名灰度动态颜色集是非常令人困惑的。为避免这种混淆,我们使用theme and
contrast to manage one set of color in
管理一组颜色light and
dark schemes instead.
而不是计划。 Example color naming in demo
演示中的示例颜色命名Airtable base

Note that a gray scale color doesn't always need to be reversed in opposite color mode. In these situations that light color remains light and dark remains dark, we simply name name it light or dark instead.
请注意,在相反颜色模式下,灰度颜色并不总是需要反转。在这些情况下,浅色保持浅色和暗色仍然是黑暗的,我们只需将其命名为亮或暗。

Once we wrap our head around this naming method, managing this architecture of color palette is easy in
一旦我们围绕这个命名方法,我们就可以轻松管理这种调色板架构Xcode. To create a color set, simply create a new
。要创建颜色集,只需创建一个新颜色Asset Catalog file → add a new
文件→添加新的Color Set → and change
→并改变Appearances to
Any, Light, Dark will do.
会做。 How to add color asset in Xcode
如何在Xcode中添加颜色资源

4. environment settings {#4-environment-settings}

One awesome feature in SwiftUI framework is the
SwiftUI框架中的一个很棒的功能是environment modifier, which provides ability to control
,提供控制的能力environment values on target view. In terms of building design system, this ability provides convenient approach to change app's font at root level. And the other advantage of using
在目标视图上。在构建设计系统方面,此功能提供了在根级别更改应用程序字体的便捷方法。而使用的另一个好处environmentValue is to change and test light and dark color schemes in development.
是改变和测试开发中的浅色和深色配色方案。

5. buttonStyle and button label {#5-buttonstyle-and-button-label}

Comparing to the old days in
与过去相比UIKit, constructing reusable buttons in SwiftUI is drastically easier. The
,在SwiftUI中构建可重用的按钮非常容易。该Button view consists of two parts, which are
由两部分组成action closure (event to be fired as button is pressed) and
闭包(按下按钮时触发的事件)和label (body of the button). The view can then be chained with a modifier
(按钮的主体)。然后可以使用修改器链接视图buttonStyle. To learn details about building reusable buttons,I recommend reading
。要了解有关构建可重复使用按钮的详细信息,我建议您阅读Alejandro's tutorial, which is comprehensive and useful.
,这是全面和有用的。

In our customized button components, first step is to create two structs, including
在我们的自定义按钮组件中,第一步是创建两个结构,包括TokenButtonLabel and
TokenButtonStyle. These two structs are programmed according to the types of buttons we have in design files. For example, there're only two types of labels: icon and text. Each type has an according
。这两个结构根据我们在设计文件中的按钮类型进行编程。例如,只有两种类型的标签:图标和文字。每种类型都有相应的init function designed with different parameters for new instances.
为新实例设计的具有不同参数的函数。

On the other hand, there're four major types of button styles: circle icon, icon, capsule and text. To follow
另一方面,按钮样式有四种主要类型:圆形图标,图标,胶囊和文本。跟随ButtonStyle protocol, a
协议,amakeBody func has to be implemented. This function brings us a
必须实现func。这个功能带给我们一个configuration property, providing a native
财产,提供本地人isPressed value to monitor if the button is pressed or not.
如果按下按钮则监视的值。

Finally, stacking on top of
最后,堆叠在上面TokenButtonLabel and
TokenButtonStyle, the endpoint of the button component API will be
,按钮组件API的端点将是TokenButton - a grouping that wraps content and style of button together, conforming to the button types in visual design system.

  • 将按钮的内容和样式包装在一起的分组,符合视觉设计系统中的按钮类型。

6. AnyView as wrapper {#6-anyview-as-wrapper}

As we're dealing with the
正如我们正在处理的那样makeBody function brought by
功能带来的ButtonStyle protocol, we found a useful tip to work with
协议,我们找到了一个有用的技巧View. To store a view in a variable, the type annotation could be indicated as
。要在变量中存储视图,可以将类型注释指示为AnyView, which works as a general container of views in SwiftUI.
,作为SwiftUI中视图的一般容器。

In our case, because we want to add the opacity modifier to
在我们的例子中,因为我们想要添加不透明度修改器configuration.label to all types of buttons, instead of doing so repeatedly in each
所有类型的按钮,而不是每个按钮重复这样做switch case, it makes more sense to chain the modifier at the end altogether. We can achieve this pattern by using the advantage of
最后,将修饰符链接在一起更有意义。我们可以利用它的优势来实现这种模式AnyView in this way:
通过这种方式:

7. Build view modifier with mutating function {#7-build-view-modifier-with-mutating-function}

To update styles of the buttons dynamically, we can build our own modifier. First instantiate customized mutable state properties in view, and then create a
要动态更新按钮的样式,我们可以构建自己的修改器。首先在视图中实例化自定义的可变状态属性,然后创建一个mutating function which returns a
返回a的函数Self type after updating the target state property.
更新目标状态属性后键入。

8. Tricky border style {#8-tricky-border-style}

One drawback of SwiftUI is styling a circle shape with circular border is not straightforward at all. I struggled for a while, and finally found a
SwiftUI的一个缺点是使用圆形边框造型圆形并不简单。我挣扎了一会儿,终于找到了一个solution here on StackOverflow. A
。一种clipShape and an
overlay modifier are required to make it work.
需要修饰符才能使其工作。


Conclusion {#conclusion}

SwiftUI is an incredible improvement Apple makes. Though flaws still exist, building a robust and flexible design system with it, and furthermore complicated UI in iOS is way efficient than ever. I hope this article is helpful for any iOS team trying to build UI, and always welcome to any feedbacks!
SwiftUI是Apple的一项令人难以置信的改进。虽然存在缺陷,但是使用它构建一个强大而灵活的设计系统,以及iOS中复杂的用户界面比以往任何时候都高效。我希望这篇文章对任何试图构建UI的iOS团队都有帮助,并且总是欢迎任何反馈!

👉 Read more of my works at
👉阅读更多我的作品vinceshao.com / Follow me on
/跟我来Twitter or
要么LinkedIn

中英文模式阅读
中文模式阅读
英文模式阅读

查看英文原文

查看更多文章

公众号:银河系1号
公众号:银河系1号

联系邮箱:public@space-explore.com
联系邮箱:public@space-explore.com

(未经同意,请勿转载)
(未经同意,请勿转载)