在iOS中实现UI:更好,更快,可扩展



几个月前,我在Netflix上遇到了一个非常有趣的纪录片系列,名为Abstract ,他们基本上是在工作场所中探索建筑,图形设计,时装等不同领域的专业设计师的作品。

很容易发现其他领域的设计人员与实现用户界面的iOS开发人员的相似之处。 例如,当设计师创建的东西大到足以分解成较小的零件时,使用“ 分而治之”之类的策略对于能够专注于将在该过程的后续阶段组装的较小零件至关重要。 。

将整个设计分解为较小的子单元,使我们能够独立考虑每个问题,从而消除了组件之间的任何依赖关系。 但是在整个过程中也需要呈现出全貌,否则,当需要将所有内容重新组合在一起时可能会出现问题。

另一方面,在观看摘要时,我注意到在诸如鞋子,横幅或建筑物之类的对象的设计过程中,最终设计在产品的生命周期内保持不变。 耐克鞋的设计在发布后不会改变,并且一旦在商店的货架上就不会有任何更新。 有时,即使20年后,设计仍保持不变,并且产品仍然是合格的。


Nike Air Max '97-帝国大厦(纽约市)

在构建大型和复杂应用程序的过程中,许多iOS开发人员花费大量时间来创建界面,定义交互和完善UI详细信息。 当然,有必要牢记整个应用程序的整体情况,但是考虑如何使所有较小的组件保持分离和独立也同样重要,因为这些较小的组件通常在以后构建时可以重复使用应用程序的其他元素。


在Badoo的iOS团队中,我们每周发布一次,所有发布都包括许多新功能,改进和影响用户界面的其他更改。 我们始终旨在快速行动并发布最高质量的功能,但是一年前,我们在用户界面开发过程中发现了一些问题,并提出了解决方案。

问题描述


我将尝试用一句话来定义问题:
iOS团队没有明确的UI开发流程。
实际上这是什么意思? 这意味着在iOS应用程序中通过更改用户界面来开发任何新功能都可能导致各种问题。 这是我们每天面临的最常见问题:

  • 与设计师的沟通既不清晰也不有效。 设计人员对我们在应用程序中实现的现有UI组件的透明度几乎没有。 这迫使他们创建看起来与现有组件非常相似的新组件。
  • UI组件的实现没有公认的模式。 每个开发人员都以不同的方式实现组件,但其中许多组件配合得并不好。
  • 代码重复导致严重的体系结构问题,除了其他问题外,还增加了循环复杂性。
  • 在同一组件的整个应用程序中应用修改总是非常困难的。
  • 除非测试未涵盖对它们的修改,否则将回归引入现有组件的风险更高。

解决这些问题将没有魔杖,因为这与过程有关。 改变工作方式需要在不同团队之间保持一致,并说服受过程影响的人们新的工作方式的好处。

“分而治之”在这里可能是一个方便的方法,从小问题开始,隔离每个问题,然后逐步建立全局解决方案。 在本文中,我将解释我们是如何实现的!

UI框架


我们从基础开始解决这个问题。 要解决的第一个问题是代码重复,我们需要统一我们的组件并将它们全部放在一个地方。

我们的解决方案是构建几个框架,我们将其命名为BadooUIKit。 想法是,它可以容纳所有UI组件,类似于Apple对UIKit所做的操作。 它包含代表一个特定应用程序(我们公司中还有其他一些应用程序,但该特定UIKit仅包含特定于Badoo应用程序的用户界面组件)的用户界面的类。

每个应用程序都有不同的调色板,字体,边距等,因此它有助于使用特定于应用程序的框架,以便在框架内也为应用程序添加样式表。



可以在不同应用程序中共享和重用的UI组件会发生什么?

为此,我们创建了另一个名为Platform_UIKit的框架。 该框架具有可在不同应用程序中使用的所有通用UI组件。

我们是否将所有UI立即迁移到新框架?

不,那将是一项艰巨的任务。 相反,我们决定在新框架内构建每个新的UI片段,并且仅在影响现有任务时才尝试移动现有组件。 在某些情况下,组件可能具有许多依赖性,因此很难从主应用程序迁移到框架。 在这些情况下,我们通常选择单独执行迁移任务。 作为初始计划的一部分,我们对字体,颜色,按钮等基本元素进行了优先排序...

后来,一旦建立了基础,我们就将聊天的整个用户界面也迁移到UI框架。 在基础架构就绪之后的某个时候,我们进行了此操作,它有助于使迁移过程更加顺畅。

旁注:
如果您对创建这些组件之一的过程感到好奇,请查看我的同事Valerii Chevtaev撰写的 这篇很棒的文章

这些框架的一个非常重要的要求是它们不得依赖于严格不是用户界面代码的其他框架或类。 例如,我们从不从主应用程序,网络层相关类,统计报告器等中导入模型。

通过将UI与其他依赖项隔离,我们使组件尽可能地可重用:



BadooUIKit可以从Platform_UIKit导入,但不是相反,因为一个简单的原因,如果Platform_UIKit依赖BadooUIKit,它将不再与应用程序无关。



在Badoo中,将这些框架添加到我们的项目中并不是很困难,并且实际上并不需要太多维护。 每个项目都不尽相同,找到合适的方法来构建结构并不总是那么简单,但无论从短期还是长期来看都是有益的。

以下是使用UIKit的一些好处:

  • 将UI组件放在一个位置可以使它们更易于查找,并且可以使项目更好地组织,而不是将它们分散在整个项目结构中。
  • 从内部依赖关系释放类有助于减少整个项目的编译时间。
  • 删除与UI代码无关的依赖项可使组件更易于重用并减少编译时间。
  • 在Badoo中更新组件 如果应用程序依赖BadooUIKit的组件,那么在整个应用程序中应用更改非常容易。
  • 隔离的组件更容易测试。
  • 如果需要,拥有单独的框架可以使其在其他应用程序中重用。 例如,创建一个列出并显示此框架中所有组件的应用程序。

画廊申请




BadooUIKit解决了许多问题,但我们知道我们仍然可以走得更远,可以对该过程进行一些改进。

如何孤立地查看所有UI组件? 我们能否设计一种方法来查找UI组件,并查看它们在不同代码颜色下的外观? 我们可以使它们易于测试吗? 设计人员是否可以通过某种方式获得我们已经在iOS中实现的所有现有UI组件的目录?

由于我们已经将BadooUIKit作为一个隔离的UI框架,因此我们决定构建一个简单的独立应用程序供内部使用。 我们介绍了Badoo Gallery。

Badoo Gallery的目的是充当开发人员,设计师甚至产品团队以友好的方式展示UI组件的工具。 在此应用程序中,我们实现了许多有助于与UI组件进行交互的不同功能。

由于此应用程序是内部工具,并非要在App Store中发布,因此可以添加我们认为必要的任何功能或工具。 在我们的案例中,我们认为以下功能特别有用:

  • 零件搜索
  • 组件名称排序
  • 标记为收藏
  • 多样式切换器-查看我们的组件在不同样式表中的外观
  • 柔韧性
  • 每秒帧数查看器



每个组件可能具有许多不同的状态,具体取决于用户输入或应用程序的固有逻辑。 例如,一个简单的UIButton定义了几种状态: 默认,突出显示,突出显示,选中和禁用。

好奇吗 在此处查看更多信息。

我们还希望能够在我们的画廊中展示所有组合。 我们在每个特定屏幕上针对任何组件执行此操作。 当然,我们自己的按钮版本可以与Apple的UIKit按钮具有不同的状态。



这是Badoo Gallery的主要优点的摘要:

  • 列出我们已在iOS中实现的所有UI组件
  • 轻松搜索和查找UI组件。 现在我们团队或产品团队中的每个人都可以看到UI组件的所有可能选项,并为其找到新的可能用法
  • 能够轻松找到已经存在的组件,使说服设计师重用它们变得容易得多
  • 像这个画廊这样的很小的项目,编译时间很短。 通过在此简易应用程序中实现UI,可以缩短整个功能的开发速度
  • 收藏夹功能可帮助我们找到当前正在实现的组件
  • 添加诸如FPS,多品牌和Flex之类的外部工具有助于理解,改善和衡量目录中的UI组件的质量
  • 现在,所有这些组件都在单独的框架中并单独呈现。 这使它们易于测试!

关于测试


通过引入新的工具集,可以解决本文中列出的大多数初始问题:



但是,仍有一些问题需要改进,还有其他问题需要解答: 进行更改时, 如何确保在进行某些更改后UI看起来像我们期望的那样? 修改“子组件”后,如何避免应用程序的其他部分或其他组件受到不利影响?

找到所有这些问题的答案的好方法是将测试添加到UI组件。 已经有很多关于如何在iOS中实现UI测试的文档。 还有许多不同的工具可用于测试应用程序用户界面的不同方面。

在Badoo中,我们决定开始使用当前最受欢迎的“工具”之一添加快照测试以进行快照测试: iOSSnapshotTestCase (以前称为FBSnapshotTestCase因为它最初是由Facebook构建并作为开源发布的)。

在以下链接中找到有关快照测试和此特定框架的更多信息:



我们需要找到一种方法来测试BadooUIKit中已经拥有的组件,以便在修改应用程序其余部分使用的组件时避免可能的回归。

我们还希望尽可能地自动化为组件添加新的快照测试的过程。

如本文前面所述,我们还有一个Gallery应用程序,该应用程序列出了所有组件以及单个组件可能具有的所有不同状态。 这非常方便,因为它允许使用Badoo Gallery作为主机应用程序添加快照测试。

BadooUIKit中实现的所有UI组件都存储在一个类(存储库或存储模式)中,该类提供对所有组件的访问。 可以实例化此Store,以显示库中的组件列表以及从快照测试类访问它们。 这意味着不必在测试级别中重复实例化和准备每个组件的不同状态的工作,因为在将组件引入Gallery应用程序界面时已经完成了这一工作。

这些是有关快照测试的一些问题。 请允许我提供一些答案:

快照图像存储在哪里?

我们将它们直接存储在git存储库中。 最初,我们认为这可能会使存储库的大小膨胀太多,但事实证明它并不太糟。 在大多数情况下,我们不是在测试全屏屏幕而是小组件,因此屏幕截图非常轻巧。 目前,我们的屏幕快照文件夹约为11Mb,我们认为可以接受。

是否已测试所有可能的模拟器中的所有可能分辨率?

不,好处不会很大,它可能导致许多问题,包括不稳定的测试,较重的快照文件夹以及维护测试套件的更多困难。 我们宁愿务实,只测试在我们的用户中最受欢迎的设备。 我们的持续集成系统还设置为使用与制作快照相同的设备模型的模拟器。

快照测试是否足以覆盖所有UI?

我不这么认为。 在Badoo,我们在应用程序的不同级别上也有不同类型的测试,例如功能测试(我们使用Calabash和KIF框架)和某些集成测试。 以我的经验,重要的是要在测试种类和满足任何应用程序需求所需的测试数量之间找到良好的平衡。

经验教训


当然,在这个新平台的构建过程中,我们的公司学到了很多东西,并且每次迭代我们仍在学习。 以上所有工具和流程都是在大约12个月的时间内引入的,并且仍在不断发展。 到目前为止,事实证明,每一个步骤对开发人员和公司都是积极的,而且从一开始我们就开始看到积极的结果。 以下是我们在此过程中吸取的一些教训:

  • 一次移动所有现有组件是一项艰巨的任务,但是创建设计系统并鼓励团队将其用作开发流程的一部分会逐步增加UI组件的数量。 在某些开发人员执行的每项任务中移动某些组件不仅会自动增加系统中UI元素的数量,而且还会解锁和释放现有元素之间的某些依赖关系。 这有助于以后移动越来越多的组件的任务。
  • 我们了解到,设计人员很乐意重用现有的组件,但是如果我们能够证明我们已经拥有一个功能完全类似于其所需功能的完全功能组件,则更容易说服他们。
  • 中长期需要节省时间是现实。 我们都知道,目前,Swift + Objective-C项目的编译时间并不是最好的。 Badoo Gallery应用程序非常轻巧,编译速度非常快。 我们了解到,最好直接使用Gallery应用程序作为游乐场来实现UI组件,然后从编译时间不太快的主应用程序中使用它们,这要好得多。
  • 将组件包含在特定的UIKit和库应用程序中,我们可以在其中轻松测试组件,这可以促进整个测试过程,并使我们可以更轻松地编写测试。


更进一步-宇宙


在Badoo中,我们关心我们的所有功能,希望它们具有统一的外观和吸引人的用户界面,以便在使用所有平台时为用户提供最佳的质量体验。 这就是我们在设计和产品团队的帮助下,在整个公司范围内进行全球变更并实施名为Cosmos的设计系统的原因。



克里斯蒂亚诺·拉斯泰利(Cristiano Rastelli )写了几篇有趣的文章 ,其中详细解释了波斯菊如何诞生。 不要错过他们!

致谢


这个项目不是一个人的工作:整个iOS团队,包括经理,开发人员和质量保证人员,都是以一种或另一种方式参与的。 我必须感谢所有人,因为我可以说他们从一开始就参与其中。

得益于Badoo出色的设计团队,他们总是愿意在改善整个公司的设计流程方面付出更多的努力。

特别感谢Alexander Zimin所做的多项改进,感谢他参加了许多与此过程有关的会议,并亲自为我提供了UI冒险方面的支持。 还要感谢Alyssa Ordillano出色的图形,这些图形极大地改善了本文的可访问性。

Source: https://habr.com/ru/post/zh-CN440920/


All Articles