使用PureLayout以编程方式创建界面元素(第1部分)

哈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.setTitlebutton.setTitleColor来设置标题及其颜色。 由于某些原因,我们不能通过直接访问按钮的titleLabel来设置按钮的标题,这是因为按钮具有不同的状态,对于许多人来说,具有不同状态的不同标题/颜色会很方便。

现在像其他组件一样,将按钮添加为子视图,并添加以下限制,使其在应有的位置显示:

 editButton.autoPinEdge(.top, to: .bottom, of: upperView, withOffset: 16.0) editButton.autoPinEdge(toSuperviewEdge: .right, withInset: 8.0) 

在这里,我们只为按钮设置了正确的上限和上限,因为我们给它提供了一个大小,它不会扩展,并且不需要其他任何内容。 现在运行项目以查看最终结果:

图片

最近的一些笔记


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

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


All Articles