作者:Weston Hanners,原文鏈接,原文日期:2017-04-19
譯者:CoderAFI;校對:Darren;定稿:CMB
用代碼來進(jìn)行自動布局
import UIKit // 導(dǎo)入 UIKit 為下面布局所用
import PlaygroundSupport // 導(dǎo)入 Playground 運(yùn)行支持的庫
// 我將會采用一種非常簡潔的方式來添加界面元素、完成布局、配置界面屬性但是不會用到 `Storybards`.
class OurAwesomeViewController: UIViewController {
// 在這里的所有UI元素, 我都會用 懶加載 方式來初始化
// 所謂懶加載也就說,只有在這些UI元素被添加到界面層級中去的時候,才會調(diào)用他們的內(nèi)聯(lián)構(gòu)造函數(shù)進(jìn)行初始化并且只會調(diào)用一次
// 理想情況下,我在這里想采用 lazy let 來強(qiáng)制保證這些UI元素在顯示之后不會改變,但是 Swift 3 并不支持
// 那如果我們直接用 let 又如何呢,答案是也不行,因?yàn)槿绻@樣的話是無法在一個方法中訪問到 self 的,這個時候 self 還沒有初始化完成
lazy var titleLabel: UILabel = {
// 初始化 label
let label = UILabel()
// 將下面的屬性禁止掉,否則會有很多布局的錯誤日志輸出.
// 我也不清楚為什么默認(rèn)值是 "true",反正現(xiàn)在用不到它了.
label.translatesAutoresizingMaskIntoConstraints = false
// 給 label 設(shè)置字體
label.font = UIFont(name: "Menlo", size: 14)
// 設(shè)置字體顏色(注意,這里我們不會牽扯到設(shè)計(jì)的東西)
label.textColor = .white
// 當(dāng)然也可以設(shè)置 label 的顯示內(nèi)容
label.text = "Awesome"
// 讓文字內(nèi)容居中
label.textAlignment = .center
return label
}()
// Button 設(shè)置也大同小異
lazy var button: UIButton = {
// 初始化
let button = UIButton()
// 禁用掉這個多余的屬性
button.translatesAutoresizingMaskIntoConstraints = false
// 設(shè)置按鈕的標(biāo)題內(nèi)容
button.setTitle("Press Me", for: .normal)
// 給按鈕綁定事件函數(shù)
button.addTarget(self,
action: #selector(OurAwesomeViewController.buttonTest),
for: .touchUpInside)
return button
}()
// 在這里添加布局代碼,當(dāng)界面準(zhǔn)備顯示在屏幕上的時候這個方法就會在 UIKit 中被調(diào)用
override func loadView() {
// 如果要采用UIKit默認(rèn)提供的view,請別忘了調(diào)用 super 的 loadView 方法,如果不用的話,也要給self.view賦值
super.loadView()
// 自定義 view 的背景色
view.backgroundColor = .blue
// StackView 控件會節(jié)省很多時間. 它會自動管理子界面的布局方式并且可以結(jié)合一些屬性設(shè)置就可以避免臃余的界面約束
// StackView 控件還可以嵌套甚至設(shè)置一些邊距以滿足各種復(fù)雜的布局情況.在我看來,這種布局方式要比設(shè)置約束簡單有效的多.
let verticalLayout = UIStackView(arrangedSubviews: [titleLabel, button])
// 同樣的禁用掉這個屬性
verticalLayout.translatesAutoresizingMaskIntoConstraints = false
// 設(shè)置垂直方向布局,并且設(shè)置填充和對齊方式.
// 這里不用記到底用了哪個屬性,只要大體有個印象,用的時候查下也可以了.
verticalLayout.axis = .vertical
verticalLayout.alignment = .fill
verticalLayout.distribution = .fill
// 如果你要設(shè)置一些邊距,可以像下面這樣做
verticalLayout.isLayoutMarginsRelativeArrangement = true
verticalLayout.layoutMargins = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
// 我們給 StackView 控件設(shè)置一些布局約束來矯正它的位置
// 這部分代碼可以抽象一下寫成一個類庫來簡化代碼.在下面文章中我會展示出來
let topConstraint = NSLayoutConstraint(item: verticalLayout,
attribute: .top,
relatedBy: .equal,
toItem: view,
attribute: .top,
multiplier: 1,
constant: 0)
let bottomConstraint = NSLayoutConstraint(item: verticalLayout,
attribute: .bottom,
relatedBy: .equal,
toItem: view,
attribute: .bottom,
multiplier: 1,
constant: 0)
let leftConstraint = NSLayoutConstraint(item: verticalLayout,
attribute: .left,
relatedBy: .equal,
toItem: view,
attribute: .left,
multiplier: 1,
constant: 0)
let rightConstraint = NSLayoutConstraint(item: verticalLayout,
attribute: .right,
relatedBy: .equal,
toItem: view,
attribute: .right,
multiplier: 1,
constant: 0)
// 現(xiàn)在添加到view中...
view.addSubview(verticalLayout)
// 添加上面的約束.
view.addConstraints([topConstraint, bottomConstraint, leftConstraint, rightConstraint])
}
// 當(dāng)按鈕被點(diǎn)擊時,這個測試方法會被調(diào)用.
func buttonTest(sender: UIButton) {
// 這里只是改變了界面的顏色
view.backgroundColor = .red
}
}
// 將上面的 view controller 綁定到 playground 上.
PlaygroundPage.current.liveView = OurAwesomeViewController()
PlaygroundPage.current.needsIndefiniteExecution = true
// 用純手工的方式編寫布局代碼可能看起來有點(diǎn)費(fèi)力,但這樣做對于了解UI元素的布局原理,位置分布,屬性設(shè)置是非常有用的.
// 采用這種方式更容易用 git 來跟蹤歷史變化, 所以在某些方面我個人認(rèn)為要比 Interface Builder 更簡單易用一些.
// 附加內(nèi)容!!!
// 你可能會想把以上代碼用到真是的 Xcode 工程中去,而不是僅僅在 Playgrounds 里面跑跑.
// 首先,當(dāng)你創(chuàng)建完工程之后,在工程文件里一般會有一個 `Main Interface` 的配置,它通常是第一個要加載的 `Storyboard`.
// 現(xiàn)在我們不用它了,可以把它刪掉.
// 下一步
// 在 AppDelegate 的 applicationDidFinishLaunchingWithOptions 中,只需要改變一行代碼即可.
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication,
willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = OurAwesomeViewController()
window?.makeKeyAndVisible()
return true
}
}
// 如果你想看我的更多文章或者跟我交流可以在 twitter(@WestonHanners) 上找我.
// 在下片文章中,我會寫一些擴(kuò)展讓上面的代碼更簡潔、易讀,大家敬請期待
譯者注:上面的這些翻譯,個人認(rèn)為只是作者為了闡述清楚代碼的原理,也就是說為什么這樣做能使代碼簡潔,而并非是每行代碼都要加注釋
本文由 SwiftGG 翻譯組翻譯,已經(jīng)獲得作者翻譯授權(quán),最新文章請?jiān)L問 http://swift.gg。