[译]iOS开发可复用框架入门教程(实例)
当你编写一个iOS应用程序时,你通常会什么都不想就导入Foundation或UIKit框架。 如果要使用字符串,日期,文件系统或线程,可以导入Foundation。如果要使用UITableViewController或UIAlertController,则可以导入UIKit。 如果你导入了UIKit,那么可以完全忽略Foundation,因为UIKit在后台会导入它。
关键是这些框架定义了你可以在代码中访问的所有方法,函数以及类。 如果忘记导入CoreBluetooth,你将无法连接到自定义蓝牙设备。 更重要的是,如果你不导入SpriteKit,那么肯定会无法将SpriteKit游戏推出市场。
这些框架都是Apple构建的。 开发人员是可以使用它们,这样我们就可以利用这些技术来让我们的iOS应用取得成功。
但什么是框架,我们为什么要使用它们?
框架是一组模块化的可复用代码,可用作更高级别软件的构建块。
使用框架的最佳理由是它们可以构建一次,并且可以重复使用无数次!
我们再来看看UIKit; UIKit由Apple开发,并不断更新。 这是一个可以被开发人员重复使用来创建新应用的项目。 我们可以在项目中使用它来定义超棒的功能,如动画,按钮(UI),转换和颜色(UI)。
我们知道Apple在iOS平台上广泛开发和使用框架,但我们呢?
创建框架是一项相对容易的任务,使用它们和让greenColor = UIColor.black一样简单。 让我们开始制作定制的Cocoa Touch Frameworks吧!
创建框架
我们将构建一个框架来模拟苹果iOS多年来一直使用的自定义状态警报。 我通常在音乐应用程序,Podcast应用程序和新闻应用程序中注意到它们。
这些自定义状态警报已经开始出现在各个地方,但没有一个是由Apple提供的公共框架来做的!
这些警报总体上相对简单。 它们由一个UIVisualEffectView(带有模糊效果)(作为背景),一个UIImage和一些文本组成。 创建一个框架来产生这些框架有多难? 其实并不糟糕!
开始
让我们打开Xcode并创建一个新项目。 选择iOS选项卡,向下滚动到框架和库,然后选择Cocoa Touch Framework。
我将命名为AOModalStatus
,其中AO
代表我的首字母缩写。
你会注意到GitHub中的这种模式,在这种模式中,人们会将框架上传到社区,可以让其他开发人员使用。
Apple的框架也遵循双字母前缀。 考虑UIKit中的UI和GLKit中的GL; 前者代表用户界面,后者代表OpenGL(或OpenGL ES),后者是GLKit构建的Open Graphics Library。
本教程使用Swift作为开发语言。 记得随时随地保存项目,让我们开始吧!
首先创建一个新文件。 在Source下,选择Cocoa Touch Class,然后从下拉列表中选择UIView。 我将它命名为AOModalStatusView。
一个XIB文件很像一个故事板,但它是用于单个视图而不是一组视图。
打开XIB文件并删除当前存在的视图。 在对象库中搜索Visual Effects View with Blur并将其拖入XIB。 在尺寸检查器中,从下拉列表中选择“Alignment Rectangle”,然后在宽度和高度中输入230个点。
现在就像故事板一样,我们将在视图中添加一些对象,这些对象将构成我们自定义的“AOModalStatusView”。
将Image View和两个Label拖动到视觉特效视图中,并将它们放置如下:
我设置图像的宽度和高度为130点。 图像水平居中,距离视觉效果视图顶部10个点。 第一个标签位于其下20个点,第二个标签位于下方5个点。 这两个标签都具有引导和尾随约束,以使它们到达视图的每一侧。 对于第二个标签,将属性检查器中的Lines选项设置为2,因为它是可能占用多行的副标题。
真绕口,但是一旦你设置了限制,最难的部分就完成了!
由于XIB是文件中的单个视图,因此应该将类分配给“File's Owner”部分。 故事板包含多个视图,所以我们不会在那里做同样的事情。
在XIB的文档大纲中(1)选择"File's Owner"。 (2)转到Identity Inspector,(3)并将Class部分分配给AOModalStatusView。
现在我们准备开始将XIB与代码合起来!
我们首先为视图中最重要的物体,图像和两个标签制作一些出口。 选择Assistant Editor,这样你可以同时查看.xib和.swift文件。
添加一个像这样的基本类:
class AOModalStatusView: UIView {
}
就像在故事板中一样,controle+点击并拖动我们几分钟前创建的类中的每个元素。 它应该看起来像这样:
如果在添加控件时遇到问题,请构建项目(command+ B)并重试。 如果这不起作用,请确保将File's Owner的类设置为“AOModalStatusView”,而不是视图的类。
现在我们可以回到标准编辑器,而不用管XIB文件。 打开AOModalStatusView.swift。
我们将创建public函数来修改这些属性,所以要隐藏对原生控件的访问。 在关键字weak之前添加关键字private,如下所示:
接着,在控件后添加以下代码:
// MARK: Set Up View
public override init(frame: CGRect) {
// For use in code
super.init(frame: frame)
setUpView()
}
public required init?(coder aDecoder: NSCoder) {
// For use in Interface Builder
super.init(coder: aDecoder)
setUpView()
}
这两个初始化器是Xcode在创建AOModalStatusView时就有了。 第一个可以直接在代码运行,而第二个需要在Interface Builder中使用。
你可能已经注意到setUpView()函数有问题......主要是因为我们还没有创建它。
但是在添加func setUpView()之前,我们需要添加一些支持变量。 将以下内容添加到控件下面的类里。
let nibName = "AOModalStatusView"
var contentView: UIView!
现在我们准备将setUpView()添加到文件中。 在我们编写的最后一个初始化代码之后添加以下代码。
private func setUpView() {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: self.nibName, bundle: bundle)
self.contentView = nib.instantiate(withOwner: self, options: nil).first as! UIView
addSubview(contentView)
contentView.center = self.center
contentView.autoresizingMask = []
contentView.translatesAutoresizingMaskIntoConstraints = true
headlineLabel.text = ""
subheadLabel.text = ""
}
这里有相当的工作量,所以我会尽快完成。 首先,我们需要将变量contentView设置为我们创建的XIB文件中的视图。 这是通过访问框架的Bundle,NIB(引用已编译的XIB)以及最后的NIB视图来完成的。
接下来,我们要使用addSubview(contentView)将我们刚刚创建的contentView添加到此类的视图中。
然后,我们将contentView的框架设置为等于该类中父视图的边界。 之后,我们想告诉它,我们不让调整大小,因为这个视图具有特定的大小。 这就是为什么我们将autoresizingMask传递给一个空数组。
最后,我们希望将标签设置为空文本,这样我们的框架完全可定制。
在AOModalStatusView.swift中,将public关键字添加到类的开头,以便稍后直接引用它。
我们几乎完成了我们的框架! 在我们构建和使用我们的框架之前还有最后一件事。 请记住我们如何将我们的控件标记为private? 添加这三个函数,这样使用框架的用户可以在他们的代码中设置图像和标签控件。
// Provide functions to update view
public func set(image: UIImage) {
self.statusImage.image = image
}
public func set(headline text: String) {
self.headlineLabel.text = text
}
public func set(subheading text: String) {
self.subheadLabel.text = text
}
瞧! 我们有一个框架,不用花多长时间就可以把它整合在一起! 但它本身并没有太大的作用,所以我们来测试一下吧!
使用定制的框架
我们将创建一个新项目来测试框架。 在我看来,互联网有很多猫,但它绝对可以使用更多的小狗! 我要模拟一个快速的小狗照片应用程序。 我们称之为幼犬乐园!
Puppy Paradise的起点可以从我的GitHub下载。
继续并在Xcode中打开启动器项目。
开始
转到项目检查器的常规选项卡并向下滚动到它所说的“Embedded Binaries.”。点击+按钮,然后添加其他。 Finder窗口将会下降,在这里需要选择我们之前创建的AOModalStatus.xcodeproj框架。 你会注意到我们的框架已添加到Project Navigator中!
现在回到Embedded Binaries并再次点击+按钮。 这一次你会看到我们添加的框架! 点击它将其添加到项目的Embedded Binaries中。
快速构建项目(command+ B)以确保事情进展顺利! 不应该有任何错误。
现在我们有了自己的框架,我们需要确保Xcode实际上引用它,然后才能开始对它进行编码。 跳转到ViewController.swift文件并在import UIKit正下方import AOModalStatus。
ViewController.swift里有当用户在查看图片时点击“保存”时执行的操作。 在saveTapped(_ :)函数内部添加presentModalStatusView()。 现在,让我们将presentModalStatusView()函数添加到该类中,以便从编译器独立出来。
func presentModalStatusView() {
let modalView = AOModalStatusView(frame: self.view.bounds)
let downloadImage = UIImage(named: "download") ?? UIImage()
modalView.set(image: downloadImage)
modalView.set(headline: "Downloading")
view.addSubview(modalView)
}
这里做了一些事情。 首先,我们初始化一个AOModalStatusView并将其命名为modalView。 然后我们使用存储在资源中的“download.png”图像创建了一个UIImage。 然后,我们将图像和一些文本设置到视图中,并将其作为子视图添加到ViewController。
在模拟器上构建并运行应用程序,并尝试保存照片! 它的工作原理! 除了少数几个方面似乎缺乏。 例如,我们无法关闭它。 也没有圆角。 最重要的是,Apple使用了微妙的动画来显示和删除它们的模态状态视图。
那么,事实证明,这些并不难实现! 由于我们导入了框架的项目而不仅仅是编译的框架,所以我们可以对其进行更改,并且每次构建PuppyParadise时Xcode都会编译它。
Timer
点击框架项目旁边的下拉菜单,然后导航到刚刚创建的AOModalStatusView.swift文件。 第一步是在给定的几秒钟后使视图自行关闭。
在contentView变量的声明之后添加var timer: Timer?。 然后添加下面的代码:
public override func didMoveToSuperview() {
// Add a timer to remove the view
self.timer = Timer.scheduledTimer(
timeInterval: TimeInterval(3.0),
target: self,
selector: #selector(self.removeSelf),
userInfo: nil,
repeats: false)
}
@objc private func removeSelf() {
self.removeFromSuperview()
}
这是一段简单的代码:“在三秒钟后消除这个视图。”
圆角
接下来是圆角,这大大降低了AOModalStatusView的清晰度。 将以下代码添加到该类中:
// Allow view to control itself
public override func layoutSubviews() {
// Rounded corners
self.layoutIfNeeded()
self.contentView.layer.masksToBounds = true
self.contentView.clipsToBounds = true
self.contentView.layer.cornerRadius = 10
}
这是可以用来创建圆角的典型代码。 需要提及的重要部分是,这是在子视图(AKA contentView)已经布置并且我们将clipsToBounds设置为true之后发生的,因此contentView中包含的子视图不能从圆角后面滑出。
现在运行它! 当我们去保存我们可爱的小狗照片几秒钟后消失,我们有圆角。
现在还有一件事要做,让它真的“弹出来!”让我们添加一些动画。
动画
可以理解的是,很多人都害怕在Swift中使用动画,但我会告诉你如何做一些如此简单而有效的事情,以便在此之后你可能会查看动画教程!
将didMoveToSuperview和removeSelf函数替换为以下内容:
public override func didMoveToSuperview() {
// Fade in when added to superview
// Then add a timer to remove the view
self.contentView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
UIView.animate(withDuration: 0.15, animations: {
self.contentView.alpha = 1.0
self.contentView.transform = CGAffineTransform.identity
}) { _ in
self.timer = Timer.scheduledTimer(
timeInterval: TimeInterval(3.0),
target: self,
selector: #selector(self.removeSelf),
userInfo: nil,
repeats: false)
}
}
@objc private func removeSelf() {
// Animate removal of view
UIView.animate(
withDuration: 0.15,
animations: {
self.contentView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
self.contentView.alpha = 0.0
}) { _ in
self.removeFromSuperview()
}
}
然后将contentView.alpha = 0.0添加到setUpView的末尾。
这里做的事情并不复杂。 在didMoveToSuperview中,我们正在将contentView转换为宽度和高度的一半。 然后我们用UIView.animate(withDuration)运行一个动画。 在这里面我们将动画设置为CGAffineTransform.identity,这是一种奇特的方式,说“它通常应该看起来如何(AKA不是它的一半大小)。”我们还将动画中的alpha值设置回1.0。 这会告诉contentView在其动画过程中淡入时会从其大小的一半增长。 动画完成后,我们立即设置最初创建的计时器。
在removeSelf 中,我们正在做相反的事情。 在动画过程中,我们希望alpha值回落到0.0(或透明),转换再次使contentView成为其平常大小的一半。 动画完成后,我们可以完全消除视图。
我想指出,所有这些代码都发生在框架内部,并且当我们在项目中使用它时,我们仍然只需要一些通用的代码行。
现在让该项目运行并尝试“保存”该照片。 你现在应该有一个工作框架和项目来测试该框架。 除此之外,你可以在另一个项目中重用此框架,甚至可以将代码推送到GitHub以供其他人开始使用!
你可以从Github上下载最终版本的Puppy Paradise和AOModalStatusView!
它是如何做的? 实现它可能有很多工作要做,但是每次你写一个新的框架,它只会变得更快,更容易!
原文:Getting Started with Reusable Frameworks for iOS Development