[译]纯代码建立 UIViewios
翻译自:swift
https://medium.com/written-code/creating-uiviews-programmatically-in-swift-55f5d14502ae/设计模式
iOS App 由许多视图组成。视图的显示依赖四个值:x,y,width,height。bash
三种方式构建视图:Storyboards
,Nib files
和编码实现
。app
UIKit 包含许多标准组件,从简单的按钮,到复杂的表格。他们用处普遍,如 UILabel 对象绘制文本字符串,UIImageView 对象绘制图像。iview
视图能够被嵌入到其余视图,从而在视图之间产生父子视图关系,一个视图的父视图被称为superview
,子视图被称为subview
。ide
如何组织你的视图关系着你的应用程序的视觉效果和事件行为。举一个例子,有两个视图,他们的父子关系决定了如何捕获事件及响应事件的顺序。相似的,当手机方向发生变化,视图的父子关系也决定了他们作如何修改。布局
Model-View-Controller 是最经常使用的设计模式。然而在 iOS App 开发过程当中,一般要面临一个问题:视图控制器经常变得过于庞大,修改和重构都很痛苦。因此 MVC 也被戏称为Massive View Controller
。ui
遵循此模式,咱们应该尽可能确保项目中的每一个类都是Controller、Model或者View。这能有效避免代码失控。咱们也能够建立其余的分组和类,但 App 的核心部分应该是这三种组成。编码
建立项目的时候,Xcode 会自动为咱们增长一个 storyboard。为了展现自定义视图,咱们干掉他先。
而后,建立两个文件:ProfileView 继承自 UIView,放到 View 分类中。ProfileViewController,继承自 UIViewController,放在 Controller 分类中。
Auto Layout 决定了屏幕上视图的 frame。每一个视图都包含约束条件,经过这些条件来计算出视图的 width,height,x,y。直接编写 Auto Layout 代码并不容易,这里咱们使用 PureLayout,它提供了功能强大,使用友好的接口来帮助咱们编写 Auto Layout
首先添加 PureLayout 到你的项目中。我使用 CocoaPods 进行包管理,它依赖 Podfile 文件:
platform :ios, '8.0'
use_frameworks!
pod 'PureLayout', '~> 2.0.5'
复制代码
执行代码以安装依赖:
pod install
复制代码
这条命令将建立一个以.xcworkspace
为扩展名的新的工程文件。如今,使用 Xcode 打开它。
ProfileView.swift
文件当前是一个自定义 UIView 类的模板:
import UIKit
class ProfileView: UIView {
}
复制代码
咱们须要初始化它。初始化在 Swift 中是值得重视的事,你将在这里了解到更多关于它的事。如今,咱们只须要知道有一个主要的初始化器负责初始化当前类全部的属性。这是一个典型的实现:
import UIKit
import PureLayout
class ProfileView: UIView {
var shouldSetupConstraints = true
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func updateConstraints() {
if(shouldSetupConstraints) {
// AutoLayout constraints
shouldSetupConstraints = false
}
super.updateConstraints()
}
}
复制代码
给自定义的视图添加约束以前,咱们要覆盖 updateConstraints
方法。这个方法在运行期间可能会被调用屡次。为了不屡次添加约束给视图,咱们须要立一个 flag(shouldSetupContraints)来标示是否已经添加过约束。这个方法的最后,咱们也必须调用父类中的同名方法。(若是你在约束发生改变以前就调用,可能会 crash)。
咱们来仿写一个 Twitter iOS app 的我的信息视图。在下面的图片中,能够看到顶部视图包括一个 Banner 图,用户头像,以及用户信息。而后下方是全部推展现在列表中以及tabbar。全部的 UIView 元素都拿紫色标注了起来。接下来咱们聚焦在 header view,橙色区域。
咱们先看主要的三部分。banner 和 用户头像使用 UIImageViews 进行展现,button 区域使用 UISegmentedControl。
首先,咱们定义三个元素在咱们的 ProfileView 类。bannerView,profileView 和 segmentedControl。
//ProfileView.swift
import UIKit
import PureLayout
class ProfileView: UIView {
var shouldSetupConstraints = true
var bannerView: UIImageView!
var profileView: UIImageView!
var segmentedControl: UISegmentedControl!
override init(frame: CGRect){
super.init(frame: frame)
}
...
复制代码
在 init 方法中,咱们初始化这些视图元素的属性。背景颜色、边框颜色和其余基本的视觉属性。初始化他们的 frame 为 zero,AutoLayout 会自动调整大小和位置。
将这些视图元素添加为 ProfileView 的子视图使用 addSubview 方法。这个方法将被操做的视图放在其余子元素的最上面。代码以下:
//ProfileView.swift
import UIKit
import PureLayout
class ProfileView: UIView {
var shouldSetupConstraints = true
var bannerView: UIImageView!
var profileView: UIImageView!
var segmentedControl: UISegmentedControl!
let screenSize = UIScreen.main.bounds
override init(frame: CGRect){
super.init(frame: frame)
bannerView = UIImageView(frame: CGRect.zero)
bannerView.backgroundColor = UIColor.gray
bannerView.autoSetDimension(.height, toSize: screenSize.width / 3)
self.addSubview(bannerView)
profileView = UIImageView(frame: CGRect.zero)
profileView.backgroundColor = UIColor.gray
profileView.layer.borderColor = UIColor.white.cgColor
profileView.layer.borderWidth = 1.0
profileView.layer.cornerRadius = 5.0
profileView.autoSetDimension(.width, toSize: 124.0)
profileView.autoSetDimension(.height, toSize: 124.0)
self.addSubview(profileView)
segmentedControl = UISegmentedControl(items: ["Tweets", "Media", "Likes"])
self.addSubview(segmentedControl)
}
...
复制代码
布局约束用来描述视图与其余视图的关系和属性。经过 NSLayoutConstraint 类来使用。
约束有如下几种:
PureLayout 定义了用来建立约束的视图属性,见图:
屏幕上有三个巨星元素,咱们要把他们的位置大小调整如 Twitter 我的页面。
//ProfileView.swift
...
override func updateConstraints() {
if(shouldSetupConstraints) {
let edgesInset: CGFloat = 10.0
let centerOffset: CGFloat = 62.0
bannerView.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets.zero, excludingEdge: .bottom)
profileView.autoPinEdge(toSuperviewEdge: .left, withInset: edgesInset)
// 👇🏽 profileView.autoAlignAxis(.horizontal, toSameAxisOf: bannerView, withOffset: centerOffset)
profileView.autoPinEdge(.bottom, to: .bottom, of: bannerView, withOffset: centerOffset)
segmentedControl.autoPinEdge(toSuperviewEdge: .bottom, withInset: edgesInset)
segmentedControl.autoPinEdge(toSuperviewEdge: .left, withInset: edgesInset)
segmentedControl.autoPinEdge(toSuperviewEdge: .right, withInset: edgesInset)
shouldSetupConstraints = false
}
super.updateConstraints()
...
}
复制代码
下面进行完成 ProfileView 的最后一步。咱们须要在咱们的 Controller(ProfileViewController)中调用。Xcode 已经建立了一个 Controller 模板,并包含 viewDidLoad: 方法。这个方法会在 Controller 显示前进行回调。接下来咱们须要实例化咱们的 ProfileView 并展现它。
//ProfileViewController.swift
import UIKit
class ViewController: UIViewController {
var profile: ProfileView!
override func viewDidLoad() {
super.viewDidLoad()
profile = ProfileView(frame: CGRect.zero)
self.view.addSubview(profile)
// AutoLayout
profile.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets.zero)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
复制代码
(最后:本文中的代码用于展现 Auto Layout。你须要补充其余代码才能使其成为一个完整的项目,加油!💃🏽👋)