哈Ha! 我向您介绍Aly Yaka
撰写的文章《
使用PureLayout以
编程方式创建UIViews约束》的翻译。

今天,我将指导您通过使用代码创建简单的移动应用程序用户界面,而无需使用情节提要或NIB。 我不会再讨论哪种方法更好,因为每种方法都有其优缺点,因此,我
将仅
留一个涉及此问题的链接 。
在本指南的第二部分中,我们将使用代码创建一些最常用的移动应用程序用户界面元素,包括导航栏,表格视图和动态大小的单元格。
复习
本教程是使用Xcode 9和Swift 4编写的。我还假设您熟悉Xcode,Swift和CocoaPods。
不用再拖延了,让我们开始创建我们的项目:一个简单的Contact Card应用程序。 本文的目的是教您如何在代码中创建应用程序的用户界面,因此,除非本指南中有此必要,否则它将不包含任何与应用程序功能有关的逻辑。
使用PureLayout以编程方式创建约束
项目设置
首先启动Xcode->“创建新的Xcode项目”。 选择“ Single View App”,然后单击“下一步”。

根据需要命名项目,我决定将其命名为ContactCard。 清除下面的所有三个选项,然后选择Swift作为编程语言,然后单击“下一步”。

在计算机上选择一个位置来保存项目。 取消选中“在Mac上创建Git存储库”。
由于我们将不在此项目中使用情节提要板或NIB,因此删除“ Main.storyboard”,可在项目导航器中找到它:

之后,在项目导航器中单击项目,然后在“常规”选项卡上,找到包含部署信息的部分,并删除“主界面”中编写的所有内容。 这就是告诉Xcode在应用程序启动时要加载哪个Storyboard文件的原因,但是由于我们只是删除了“ Main.storyboard”,因此Xcode找不到该文件,这将导致应用程序崩溃。

创建一个ViewController
如果现在运行该应用程序,则会出现黑屏,因为该应用程序现在没有用户界面的源,因此在下一部分中,我们将创建它。 打开“ AppDelegate.swift”,然后在
application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?)
内部
application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?)
,粘贴以下代码片段:
self.window = UIWindow(frame: UIScreen.main.bounds) let viewController = ViewController() self.window?.rootViewController = viewController self.window?.makeKeyAndVisible()
该代码为用户与应用程序的交互提供了一个窗口,通常可以在“ ViewController.swift”中找到该窗口。 要快速验证一切正常,请转到“ ViewController.swift”,然后在
viewDidLoad()
方法中插入以下行:
self.view.backgroundColor = .blue
现在运行该应用程序。
要在Xcode中的文件之间导航,请使用“⇧⌘O”热键,然后输入要查找的文件名甚至代码片段,屏幕上会出现可供选择的文件列表。
启动应用程序后,这应该是模拟器屏幕上的结果:

当然,我们不会使用这种令人讨厌的蓝色,因此只需在
viewDidLoad ()
内部将
.blue
替换为
.blue
,
.white
将背景更改为白色。
UI开发
要创建我们的用户界面,我们将使用一个使生活更加轻松的
库 。 要安装PureLayout,必须首先打开终端并输入cd,然后输入空格,将项目文件夹拖到终端中,然后按“ Enter”。 现在在终端中运行以下命令:
这应该是第二条命令后终端的输出:

之后,关闭Xcode,在Finder中打开文件夹,您应该找到“ <您的项目名称> .xcworkspace”。 如果我们需要使用CocoaPods,我们将打开它来访问我们的应用程序。 现在找到名为“ PodFile”的文件,并将以下行写在
use_frameworks!
pod “PureLayout”
在终端中再次运行
pod install
,然后按“ Command + B”构建项目。
喝咖啡休息时间
现在一切都已设置好,让我们从实际工作开始。 转到“ ViewController.swift”并拿起一杯咖啡,因为最终结果将是这样的:

创建ImageView
在
import UIKit
下插入
import PureLayout
行,以便可以在此文件中使用该库。 然后,在类声明下并且在任何函数之外,我们首先创建如下的懒惰(懒惰)
Avatar ImageView
变量:
lazy var avatar: UIImageView = { let imageView = UIImageView(image: UIImage(named: "avatar.jpg")) imageView.autoSetDimensions(to: CGSize(width: 128.0, height: 128.0)) imageView.layer.borderWidth = 3.0 imageView.layer.borderColor = UIColor.lightGray.cgColor imageView.layer.cornerRadius = 64.0 imageView.clipsToBounds = true return imageView }()
对于图像,将要用作头像的任何图像保存在桌面上,并将其拖到<您的项目名称>文件夹的Xcode中,在我的情况下称为“ ContactCard”,然后选中“如果需要,复制项目”框。

之后,在UIImage声明中而不是“ avatar.jpg”中写入该文件的名称及其扩展名。
对于那些不知道的人,惰性变量与普通变量相似,不同之处在于直到第一次需要或调用它们之前,它们才被初始化(或分配了一些内存空间) 。 这意味着在初始化视图控制器时不会初始化惰性变量,而是在真正需要它们时会期望稍后一点,从而节省了其他进程的处理能力和内存空间。 这在初始化用户界面组件时特别有用。
PureLayout的实际应用
如您在初始化内部所看到的,
imageView.autoSetDimensions (to: CGSize (width: 128.0, height: 128.0))
行
imageView.autoSetDimensions (to: CGSize (width: 128.0, height: 128.0))
实际上就是PureLayout。 在一行中,我们为UIImageView的高度和宽度都设置了一个限制,并且所有必要的NSLayoutConstraints都被创建,而无需进行大量的函数调用。 如果您正在以编程方式处理创建限制,那么您很可能已经爱上了这个出色的库。
为了使图像变圆,我们将其角半径设置为宽度或高度的一半,即64.0点。 另外,将
clipsToBounds
属性设置为
true
,它告诉图像应该裁剪
clipsToBounds
我们刚刚设置的半径范围之外的所有内容。
然后,我们继续创建一个UIView,它将作为灰色绘制的头像后面的视图顶部。 为此视图声明以下惰性变量:
lazy var upperView: UIView = { let view = UIView() view.autoSetDimension(.height, toSize: 128) view.backgroundColor = .gray return view }()
添加子视图
在继续之前,让我们创建一个
func addSubviews ()
函数,该函数将我们刚刚创建的视图(以及我们将要创建的所有其他视图)作为子视图添加到视图控制器中:
func addSubviews() { self.view.addSubview(avatar) self.view.addSubview(upperView) }
现在
viewDidLoad (): self.addSubviews ()
添加到
viewDidLoad (): self.addSubviews ()
设定限制
为了了解我们已经走了多远,让我们对这两种设置限制。 创建另一个名为
func setupConstraints()
并插入以下约束:
func setupConstraints() { avatar.autoAlignAxis(toSuperviewAxis: .vertical) avatar.autoPinEdge(toSuperviewEdge: .top, withInset: 64.0) upperView.autoPinEdge(toSuperviewEdge: .left) upperView.autoPinEdge(toSuperviewEdge: .right) upperView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .bottom) }
现在在
viewDidLoad()
内部调用
setupConstraints()
,如下所示:
self.setupConstraints()
。 在调用
addSubviews()
之后添加此内容。 这应该是最终结论:

将头像带到最前沿
不幸的是,这不是我想要的。 如您所见,我们的
upperView
位于头像上。 这是由于以下事实:我们在
upperView
之前添加了一个头像作为
subviews
,并且由于这些子视图以某种形式位于堆栈中,因此我们得到了此结果。 要解决此问题,我们可以简单地将这两行相互替换,但是我想向您展示另一个技巧,即:
self.view.bringSubview (toFront: avatar)
。
此方法会将头像从堆栈的底部转移到顶部,因此请选择最喜欢的方法。 当然,出于可读性考虑,最好以子视图相交的顺序添加子视图,同时要记住第一个添加的子视图将在堆栈的底部,因此任何其他相交的视图都将出现在其顶部。
这实际上是这样的:

创建分段控件
接下来,我们将创建一个分段控件,它是一个包含三个部分的灰色条。 实际上,分段控件很容易创建。 请执行以下操作:
lazy var segmentedControl: UISegmentedControl = { let control = UISegmentedControl(items: ["Personal", "Social", "Resumè"]) control.autoSetDimension(.height, toSize: 32.0) control.selectedSegmentIndex = 0 control.layer.borderColor = UIColor.gray.cgColor control.tintColor = .gray return control }()
我相信一切都清楚了,唯一的区别是初始化后,我们为其提供了一个字符串数组,每一行代表我们所需部分之一的标题。 我们还将
selectedSegmentIndex
设置为0,这告诉分段控件在初始化期间选择/选择第一个分段。 剩下的只是一种风格。
现在,让我们继续并将其添加为子视图,方法是在
addCubviews(): self.view.addSubview(segmentedControl)
函数的末尾插入以下行:
addCubviews(): self.view.addSubview(segmentedControl)
,其局限性如下:
segmentedControl.autoPinEdge(toSuperviewEdge: .left, withInset: 8.0) segmentedControl.autoPinEdge(toSuperviewEdge: .right, withInset: 8.0) segmentedControl.autoPinEdge(.top, to: .bottom, of: avatar, withOffset: 16.0)
我们告诉分段控件,我们希望将其附加到其超级视图的左侧,但是我们要稍微增加间隔,而不是将其直接附加到屏幕的边缘。 如果您注意到,我使用所谓的八点网格,其中所有距离和大小都是八的倍数。 我在分段控件的右侧执行相同的操作。 至于最后一个限制,他说以16点的间隔将一个顶点附加到化身的底部。
将以上限制添加到
func setupConstraints()
运行代码并确保其外观如下:

添加按钮
现在,我们将转到教科书用户界面的最后一部分,即“编辑”按钮。 添加以下惰性变量:
lazy var editButton: UIButton = { let button = UIButton() button.setTitle("Edit", for: .normal) button.setTitleColor(.gray, for: .normal) button.layer.cornerRadius = 4.0 button.layer.borderColor = UIColor.gray.cgColor button.layer.borderWidth = 1.0 button.tintColor = .gray button.backgroundColor = .clear button.autoSetDimension(.width, toSize: 96.0) button.autoSetDimension(.height, toSize: 32.0) return button }()
不必担心初始化有多大,但是请注意如何通过调用
button.setTitle
和
button.setTitleColor
来设置标题及其颜色。 由于某些原因,我们不能通过直接访问按钮的
titleLabel
来设置按钮的标题,这是因为按钮具有不同的状态,对于许多人来说,具有不同状态的不同标题/颜色会很方便。
现在像其他组件一样,将按钮添加为子视图,并添加以下限制,使其在应有的位置显示:
editButton.autoPinEdge(.top, to: .bottom, of: upperView, withOffset: 16.0) editButton.autoPinEdge(toSuperviewEdge: .right, withInset: 8.0)
在这里,我们只为按钮设置了正确的上限和上限,因为我们给它提供了一个大小,它不会扩展,并且不需要其他任何内容。 现在运行项目以查看最终结果:

最近的一些笔记
练习,根据需要添加任意数量的界面元素。 创建您认为困难的任何应用程序的视图。 从简单开始,逐步增加难度。 尝试在一张纸上绘制UI组件,以想象它们如何组合在一起。
在第二部分中,我扩展了本指南,以在代码中创建导航栏,表格视图和动态大小的单元格。