功能视图

视图是iOS应用程序的基础构建块。

随着您获得更多的经验或开始从事复杂的项目,编写视图的方式将会发展,并且您将开始更加关注设计模式,可测试性和一致性。 有很多方法可以尝试! 我们在iZettle的经验使我们找到了一种有趣的实用方式来思考我们想分享的观点。

假设我们有一个视图层次结构,可以在几个地方重用。 它由一个标签和一个文本字段组成,它们看起来像这样:

我们通常将如何组织与它们相关的代码?

从熟悉的方法开始

实现此层次结构的一种流行方法是创建UIView的子类,该子类将知道如何呈现其子视图。

我们将其称为PriceView

如您在图像中所见,在这种情况下,两个子视图很简单,因此不需要任何特殊的渲染代码。 我们将实例化它们,将它们添加为子视图,并指定样式和布局规则。 像这样:

传递输入数据

我们的PriceView有一些输入和输出。 让我们讨论它如何接收金额更新和描述占位符。

  • 在上例中,子视图被公开为公共属性。 这样, PriceView不会封装其实现细节,无论显示在哪里,我们都将紧密耦合。 例如,如果文本字段需要替换为文本视图,则我们将不得不在多个位置更改代码。 我们可以做得更好!
  • 我们可以将子视图设置为私有属性,并仅公开采用输入的配置方法并将其内部传递给子视图。 这意味着在我们的实现中,我们将在一个地方创建子视图,并在另一个地方设置它们的状态。
  • 现在让我们尝试一种更被动的方式来处理输入数据。 我们可以通过初始化程序传递所有数据源。 对于应该在外部进行更改的事情,我们可以传递一个可观察的类型。 在不同的反应式框架中对此有很多看法-在我们的示例中,我们将使用iZettle的Flow框架及其ReadSignal类型。 对于不变的东西,例如占位符文本,我们只需传递值即可。
    这种方法使我们可以在一处创建子视图,对其进行订阅并对所有可观察对象做出反应。

处理用户输入

触摸事件和其他用户交互如何?

  • 我们可以使用熟悉的委托模式 -在PriceView中配置一个可以处理事件的对象。 如果我们希望有一个对象对PriceView的输出做出反应,但不缩放到多个对象,则此方法效果很好。
  • 另外,对于广播到多个对象,我们可以使用通知和观察模式 。 但是,实施观察者管理可能是一项繁琐的任务[1]。
  • 与输入一样,我们也可以在此处使用反应模式 。 如果PriceView公开了一个可观察的类型,我们可以通过它广播事件,而不必关心有多少对象观察到它-零个,一个或多个。 Flow的信号类型也可以在这里为我们提供帮助。

放在一起

因此,我们已经看到将信号用于输入和输出具有一些好处,并且可以将它们放在一起。

在这一点上,我们可以质疑为什么我们应该首先继承UIView ,因为我们没有绘制任何复杂的东西。

我们可以通过将输入移至结构的属性,并将视图创建移至返回简单UIView和输出信号的函数来进行清理。

酷吧?

注意:我们将PriceView的名称更改为PriceDescriptionEntry ,因为它更清楚地表达了我们想要表示的意图。 PriceDescriptionEntry现在是一个定义,可以多次传递和实例 以创建视图。

我们如何使用这个

iZettle的应用程序已经发展了八年,并且代码库和团队正在迅速增长。 为了保持一致,我们倾向于将类似的解决方案应用于相似的问题。 我们在应用程序的许多部分中都使用了响应模式,并且喜欢将我们学到的知识也应用到视图中的想法。

那么我们如何在实践中应用它呢?

  • 我们尝试并遵循上述“组合”方法。 我们使用通用协议对其进行了形式化,因此任何可表示的事物都可以实现 。 我们也有很多帮助者,使我们能够创作出漂亮的东西。
  • 如果需要自定义渲染/复杂的触摸事件处理,我们将创建UIView的子类来处理该事件,并从materialize()函数返回它。

这就是全部? 当然不是!

要了解有关该想法如何演变为框架的更多信息,请查看
关于创建Presentation Framework的博客文章。

请继续关注更多博客文章,或者如果您等不及,请访问Jobs.izettle.com😜。