在 Swift 3 上对视图控件实践面向协议编程

本文讲的是在 Swift 3 上对视图控件实践面向协议编程,


学习如何对 buttonlabelimageView 创建动画而不制造一串乱七八糟的类

你可能听人说过,学到了知识却缺失了行动就好比人长了牙却还老盯着奶喝一样。那好,我们要怎样开始在我的应用中实践面向协议编程?

为了能更加高效的理解下面的内容,我希望读者能够明白 Complection Handlers,并且能创建协议的基本实现。如果你还不熟悉他们,可以先查看下面的文章和视频再回来接着看:

前景提要:

看完这篇文章你会学到这些内容

你将会明白如何使用协议给 UIButtonUILabelUIImageView 等 UI 组件添加动画,同时我也会给你演示传统方法和使用 POP 方法之间的差异。

UI

这个演示程序名为「欢迎来到我家的聚会」。我将会使用这个应用程序来验证你是否获得邀请,你必须输入你的邀请码。这个应用并没有逻辑判断,所以只要你按下按钮,无论如何动画都将会被执行。 将会有 passcodeTextFieldloginButton,errorMessageLabel 和 profileImageView 四个组件参与动画过程。

这里有两个动画:1. 左右晃动 2. 淡入淡出

不用担心遇到问题,现在我们干的就像写流水账一样,如果你不耐烦了,直接滑动到下面下载源代码就可以了,

我们接着来

想要完整的在应用中体验 POP 的魔力,那就先让我们和传统方式来比较一下,假设你想给 UIButton 和 UILabel 添加动画,你先将他们都子类化,再给他们添加一个方法:

class BuzzableButton: UIButton {
    func buzz() { /* Animation Logic */ }
}

class BuzzableLabel: UIButton {
    func buzz() { /* Animation Logic */ }
}

然后,在你点击登录按钮的时候让他抖动

@IBOutlet wear var errorMessageLabel: BuzzableLabel!
@IBOutlet wear var loginButton: BuzzableButton!

@IBAction func didTapLoginButton(_ sender: UIButton) {
    errorMessageLabel.buzz()
    loginButton.buzz()
}

看到我们是如何写重复的代码了吗?这个动画逻辑至少有 5 行,更好的选择是使用 extension,因为 UILabel 和 UIButton都继承自 UIView,我们可以给它添加这样的扩展:

extension UIView {
    func buzz() { /* Animation Logic */ }
}

然后,BuzzableButton 和 BuzzableLabel 就都有了 buzz 方法。现在,我们不用再写重复的内容了。

class BuzzableButton: UIButton { }
class BuzzableLabel: UIButton { }

@IBOutlet wear var errorMessageLabel: BuzzableButton!
@IBOutlet wear var loginButton: BuzzableLabel!

@IBAction func didTapLoginButton(_ sender: UIButton) {
    errorMessageLabel.buzz()
    loginButton.buzz()
}

那好,为什么要用 POP? 

正如你锁看到的,errorMessageLabel 将会显示 "Please enter valid code ",并且具有淡入和淡出效果,在传统形式下我们会怎么做?

有两种方式来完成这一步。首先,你可以再向 UIView 添加一个方法

// Extend UIView
extension UIView {
    func buzz() { /* Animation Logic */ }
    func pop() { /* UILabel Animation Logic */ }
}

然而,如果我们把方法添加到 UIView,那么不光是 UILabel,其他所有 UI 组件都将会拥有 pop 这个方法,继承了不必要的函数让它变得过于臃肿了。

而另一种方式则是创建 UILabel 的子类:

// Subclass UILabel
class BuzzableLabel: UILabel {
    func pop() { /* UILabel Animation Logic */ }
}

这样是可用的,我们可能会希望将类名改成 BuzzablePoppableLabel 来更清晰的声明它的用途。

现在,如果你想给 UILabel 添加更多的方法,你就要再次给他起个新名字比如BuzzablePoppableFlashableDopeFancyLovelyLabel,这恐怕不是一个可维护的方案,我们可能需要想想别的方法。

面向协议编程

看到这里还没给文字点赞吗?动动手指点个赞然后继续往下看吧

我们受够了各种子类了,让我们先来创建一个协议,让他抖动起来。

我并没有在这里写动画代码,因为它很长,并且 gist 在移动设备上支持不佳

protocol Buzzable {}

extension Buzzable where Self: UIView {
    func buzz() { /* Animation Logic */ }
}

任何 UI 组件只要遵循 Buzzalbe 协议就能拥有 buzz 方法,与直接给 UIView 添加 extension 不同,只有遵循协议的类才会拥有这些方法。另外,where Self: UIView 表示只有 UIView 或者从 UIView 继承的组件才能够遵循这个协议。

现在,我们将 Buzzable 应用给了 loginButtonpasscodeTextFielderrorMessageLabel 和 profileImageView。等等,那 Poppable 呢?

看起来差不多的:

protocol Poppable { }

extension Poppable where Self: UIView {
    func pop() { /* Pop Animation Logic */ }
}

是时候动真格的了!

class BuzzableTextField: UITextField, Buzzable { }
class BuzzableButton: UIButton, Buzzable { }
class BuzzableImageView: UIImageView, Buzzable { }
class BuzzablePoppableLabel: UILabel, Buzzable, Poppable { }

class LoginViewController: UIViewController {
    @IBOutlet weak var passcodTextField: BuzzableTextField!
    @IBOutlet weak var loginButton: BuzzableButton!
    @IBOutlet weak var errorMessageLabel: BuzzablePoppableLabel!
    @IBOutlet weak var profileImageView: BuzzableImageView!

    @IBAction func didTabLoginButton(_ sender: UIButton) {
        passcodTextField.buzz()
        loginButton.buzz()
        errorMessageLabel.buzz()
        errorMessageLabel.pop()
        profileImageView.buzz()
    }
}

POP 是一件很酷的事情,你可以在任何时间把这个协议应用给任何一个 UI 组件都不需要再去子类化任何东西。

class MyImageView: UIImageVIew, Buzzable, Poppable { }

现在,你可以更加灵活的给类来命名,因为你已经知道它遵循了哪些协议,并且每个协议的名称就能很清晰的描述它在干什么。所以你不会再有 MyBuzzablePoppableProfileImage 这样的东西。

TL;DR

少用子类

灵活的类名

就像一个 Swift 开发者一样

下一步

一旦我这篇文章(译注:指英文原文)获得超过 200 个 like,并且你想了解如何将 POP 运用在 UITableView 和UICollectionView 中,请关注我的 Medium。

资源

源代码

Last Remarks

我想希望你已经学到了一些新知识,如果有的话,请给本文点赞。如果你觉得本文内容很有用,请将本文分享给大家,以便世界各地的 iOS 开发者都能运用面向协议编程,以在写视图控件的时候写更少和更清晰的代码。回顾于 EST 时间星期六上午 8 点。

Swift 会议

Andyy Hope ,我的一个朋友,目前正在组织在澳大利亚墨尔本最大的 Swift 会议之一 ———— Playground,我只是想让大家都知道这个。 有来自市值亿万美元公司的讲者,比如 Instagram,IBM,Meet Up,Lyft,Facebook,Uber。 在这里 网站 你可以了解到更多信息。

https://twitter.com/playgroundscon

Shoutout

感谢大家给我的支持:

我本周在韩国首尔遇见了 David,他在蓝牙上需要一些帮助,我喜欢说...「,让我试试」。

即将开课

我目前正在制作一个课程,和 Bob 一起在 Udemy 上教 UIKit 基本原理,这个课程是为中级 Swift 开发者设计的,目前还没有完成。自上个月以来已经有超过 180 个读者给我发邮件,如果你也想加入我们那就给 bobleesj@gmail.com 发邮件吧,直到课程发布前都是免费的。

辅导

如果你正需要帮助来成为一个 iOS 开发者或者创建你喜欢的应用来帮助大家,请联系我活动更多的细节。





原文发布时间为:2017年2月8日


本文来自合作伙伴掘金,了解相关信息可以关注掘金网站。

时间: 2017-10-18

在 Swift 3 上对视图控件实践面向协议编程的相关文章

Swift 中的面向协议编程是如何点亮我的人生的

本文讲的是Swift 中的面向协议编程是如何点亮我的人生的, 面向对象编程至今已经使用了数十年了,并且成为了构建大型软件约定俗成的标准.作为iOS编程的中心思想,遵循面向对象规范来编写一个 iOS 的应用几乎不可能实现.虽然面向对象有很多优点比如封装性,访问控制和抽象性,但是它也自带有固有的缺点. 大多数类的情况下,当一个单继承的类需要更多不同类中的函数功能时,你会倾向于使用多继承来实现. 但是大部分的编程语言不支持这一特性,而且会导致类的继承关系变得复杂. 在多线程环境下,如果所有对象在函数中

Qt qml中listview 列表视图控件(下拉刷新、上拉分页、滚动轴)_Android

Qt qml listview下拉刷新和上拉分页主要根据contentY来判断.但要加上顶部下拉指示器.滚动条,并封装成可简单调用的组件,着实花了我不少精力:) 先给大家展示下效果图: [功能] 下拉刷新和上拉分页逻辑 /下拉刷新 /上拉更多 /滚动栏 /工具栏半拉显隐 Author: surfsky.cnblogs.com Lisence: MIT 请保留此文档声明 History: init. surfsky.cnblogs.com, 2015-01 add initPosition pro

列表视图控件介绍

本课中我们将学习如何创建和使用列表视图控件. 理论:列表视图控件和树型视图.丰富文本编辑控件一样是通用控件的一种.可能您都已经知道了列表视图控件,只不过是不知道它的确切名字而已.列表视图控件可以用来很好地显示项目.在这方面它和列表框相同,只不过它的性能更强.有两种方法创建一个列表视图控件.第一种也是最简单的方法是:用资源编辑器来创建它.用该种方法只是不要忘记在您的代码(的任何位置处)加入对InitCommonControls函数的调用(记得吗,调用该函数只是为了隐式地加载包含通用控件的DLL).

Android视图控件架构分析之View、ViewGroup_Android

在Android中,视图控件大致被分为两类,即ViewGroup和View,ViewGroup控件作为父控件,包含并管理着子View,通过ViewGroup和View便形成了控件树,各个ViewGoup对象和View对象就是控件树中的节点.在控件树中,以树的深度来遍历查找对应的控件元素,同时,上层控件负责子控件的测量与绘制,并传递交互事件. Android控件树: AndroidUI界面架构图: 一.测量View的工具类:MeasureSpec 1.MeasureSpec包含了测量的模式和测量的

iOS应用开发中视图控件UIWindow的基本使用教程_IOS

一.简单介绍 iPhone应用程序通常只有一个窗口,表示为一个UIWindow类的实例.应用程序在启动时(或者从nib文件进行装载)创建这个窗口,并往窗口中加入一或多个视图并显示出来.之后我们很少需要再次引用它.UIWindow对象是所有UIView的根,管理和协调的应用程序的显示.一般应用程序只有一个UIWindow对象,即使有多个UIWindow对象,也只有一个UIWindow可以接受到用户的触屏事件. 在IOS中,UIWindow对象并没有像windows应用程序中常见的关闭框或标题栏这样

Android视图控件架构分析之View、ViewGroup

在Android中,视图控件大致被分为两类,即ViewGroup和View,ViewGroup控件作为父控件,包含并管理着子View,通过ViewGroup和View便形成了控件树,各个ViewGoup对象和View对象就是控件树中的节点.在控件树中,以树的深度来遍历查找对应的控件元素,同时,上层控件负责子控件的测量与绘制,并传递交互事件. Android控件树: AndroidUI界面架构图: 一.测量View的工具类:MeasureSpec 1.MeasureSpec包含了测量的模式和测量的

汇编教程之树型视图控件

本课中,我们将学习如何使用树型视图控件.另外还要学习如何在树型视图中完成拖-拉动作,以及如何使用图象列表. 理论: 树型视图是一种特别的窗口,我们可以使用它一目了然地表示某种层次关系.譬如象在资源管理器中左边窗口中的就是树型视图.您可以调用CreateWindowEx来创建树型视图,传递一个类名""SysTreeView32"",或者您也可以把它放到一个对话框中去.不要忘了在您的代码中加入InitCommonControls函数. 树型视图有几种特有的风格.下面是几

树型视图控件详解

本课中,我们将学习如何使用树型视图控件.另外还要学习如何在树型视图中完成拖-拉动作,以及如何使用图象列表. 理论:树型视图是一种特别的窗口,我们可以使用它一目了然地表示某种层次关系.譬如象在资源管理器中左边窗口中的就是树型视图.您可以调用CreateWindowEx来创建树型视图,传递一个类名""SysTreeView32"",或者您也可以把它放到一个对话框中去.不要忘了在您的代码中加入InitCommonControls函数. 树型视图有几种特有的风格.下面是几种

vc++在MFC对话框上用程序生成控件(比如Text和Edit控件),求如何实现?

问题描述 vc++在MFC对话框上用程序生成控件(比如Text和Edit控件),求如何实现? vc++我想在MFC对话框上用程序生成控件(比如Text和Edit控件),求如何实现?(不是用工具条拖动控件到对话框上) 1.用程序生成控件2.控件在对话框上准确定位 求大神指导下 解决方案 一个 CreateWindow() 就能搞定,例子很多,自己找. 解决方案二: MFC我没有研究过,但我想MFC中应该可以调用Win32API吧,可以看看这几个,虽然不是MFC,但是在MFC里想必是可以用的.htt