Open mmoaay opened 6 years ago
title: "iOS:在 Swift 中优雅的配置 IBOutlets 的样式" date: tags: [Swift] categories: [Tomasz Szulc] permalink: ios-a-beautiful-way-of-styling-iboutlets-in-swift keywords: custom_title: description:
原文链接=http://szulctomasz.com/ios-a-beautiful-way-of-styling-iboutlets-in-swift/ 作者=Tomasz Szulc 原文日期=2016-06-22 译者=wiilen 校对= 定稿=
最近我正纠结于如何配置视图的样式。通常我会尽量在 storyboard 中完成相关工作,然后创建 IBOutlet
引用,并在 view controllers 中完成剩下的工作 —— 这并不是最理想的方法,我也知道。
现在的问题会更复杂一些。我在 storyboards 中使用大量的占位视图,这些视图将会持有更复杂的自定义控件。这些类型的控件在 storyboard 中只有占位引用,难以在 storyboard 中进行完全的自定义。我的意思是,你也可以使用 @IBDesignable
,但在一些情况下你将会重复定义内部视图的属性。我十分推崇将控件内的视图暴露出来并在外部进行自定义的做法 —— 但这篇文章中将不会涉及这些。
因此,我在思考如何在不扰乱 view controller 中的代码与逻辑的情况下配置这些控件。经过一番 Google 我发现了 @NatashaTheRobot 写的文章:iOS:在 Swift 中优雅的配置 IBOutlets 的样式(你可以先读读这篇文章)(译者注:与本文的标题确实是一样的)。
原文中示例代码如下:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myLabel: UILabel! {
didSet {
myLabel.textColor = UIColor.purpleColor()
}
}
@IBOutlet weak var myOtherLabel: UILabel! {
didSet {
myOtherLabel.textColor = UIColor.yellowColor()
}
}
@IBOutlet weak var myButton: UIButton! {
didSet {
myButton.tintColor = UIColor.magentaColor()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
她所提出的方法确实是挺优雅的,我选择使用这种方法试试。然后我意识到我需要对控件进行大量的自定义,于是我马上就不喜欢这种做法了,甚至有些讨厌它,因为我发现 view controller 会变得越来越大。
使用这种方法对 outlets 进行样式配置需要 2 + n 行代码,n 指的是样式代码的行数。为了可读性你可能需要添加一些空行。使用 10 个属性进行样式配置就需要添加大量的额外代码,这些我们也许可以避免。
我不是说这种方法不好,你一定不能这么做,我不是这个意思。实际上我也喜欢这种方法,但对我目前的项目来说这不是最好的解决方法。
举一个更简单的例子。我想要配置一些 lable、一个 button 与一个 view,你也可以想象一些与实际更贴近的例子,就像我在上面提到的一样 —— 每个控件都是自定义的,你需要在某个地方配置样式 —— 你也可以通过创建一些 DRY 方法来避免重复的配置代码 —— 我希望你写了这样的代码 :)
class ManyLabelsViewController: UIViewController {
@IBOutlet private var label1: UILabel!
@IBOutlet private var label2: UILabel!
@IBOutlet private var label3: UILabel!
@IBOutlet private var label4: UILabel!
@IBOutlet private var label5: UILabel!
@IBOutlet private var label6: UILabel!
@IBOutlet private var button1: UIButton!
@IBOutlet private var view1: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// 一些其他代码...
}
}
让我们来添加一些样式。
import UIKit
class ManyLabelsViewController: UIViewController {
@IBOutlet private var label1: UILabel! {
didSet {
label1.textColor = UIColor.redColor()
label1.font = UIFont.systemFontOfSize(20)
label1.backgroundColor = UIColor.blueColor()
}
}
@IBOutlet private var label2: UILabel! {
didSet {
label2.layer.borderColor = UIColor.yellowColor().CGColor
label2.layer.borderWidth = 1
label2.backgroundColor = UIColor.blueColor()
label2.clipsToBounds = true
}
}
@IBOutlet private var label3: UILabel! {
didSet {
label3.textColor = UIColor.purpleColor()
}
}
@IBOutlet private var label4: UILabel! {
didSet {
label4.textAlignment = .Center
label4.textColor = UIColor.grayColor()
}
}
@IBOutlet private var label5: UILabel! {
didSet {
label5.backgroundColor = UIColor.greenColor()
label5.font = UIFont.boldSystemFontOfSize(28)
}
}
@IBOutlet private var label6: UILabel! {
didSet {
label6.lineBreakMode = .ByClipping
label6.numberOfLines = 0
}
}
@IBOutlet private var button1: UIButton! {
didSet {
button1.layer.borderWidth = 1
button1.layer.borderColor = UIColor.blueColor().CGColor
}
}
@IBOutlet private var view1: UIView! {
didSet {
view1.backgroundColor = UIColor.cyanColor()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// 一些其他代码...
}
}
Wow... view controller 中已经有 65 行代码,而现在还没有任何逻辑代码。在我们开始配置样式前就有 17 行。这看起来可不像一个优雅的方法。你可以看见那些属性声明吗?当然,它们清楚可见。
当你想要创建一些只用来配置样式的 outlets 时,这将变得更糟。如果没有这些自定义的样式,你就不需要创建这样的 outlet 了。
有比这更好的解决办法吗?有的。是否存在通用的解决方案?不一定,这种方法适用于我的项目,比起上面所说的办法,我得到了更好的结果。
既然我们总要使用 storyboard,为什么不创建一些样式对象来帮助我们做这些脏活?要创建这个对象,只需要拖动 Object 对象到 storyboard 的 view controller 中,并创建以 ViewControllerStyle
为后缀的类,连接 outlets 并进行样式配置。你也可以在许多对象中创建对特定的视图/控件的引用,而不仅是 view controller。
这样做之后,样式代码可以都放到 ManyLabelsViewControllerStyle
类中。
class ManyLabelsViewControllerStyle: NSObject {
@IBOutlet private weak var label1: UILabel!
@IBOutlet private weak var label2: UILabel!
@IBOutlet private weak var label3: UILabel!
@IBOutlet private weak var label4: UILabel!
@IBOutlet private weak var label5: UILabel!
@IBOutlet private weak var label6: UILabel!
@IBOutlet private weak var button1: UIButton!
@IBOutlet private weak var view1: UIView!
func style() {
styleLabel1()
styleLabel2()
styleLabel3()
styleLabel4()
styleLabel5()
styleLabel6()
styleButton1()
styleView1()
}
private func styleLabel1() {
label1.textColor = UIColor.redColor()
label1.font = UIFont.systemFontOfSize(20)
label1.backgroundColor = UIColor.blueColor()
}
private func styleLabel2() {
label2.layer.borderColor = UIColor.yellowColor().CGColor
label2.layer.borderWidth = 1
label2.backgroundColor = UIColor.blueColor()
label2.clipsToBounds = true
}
private func styleLabel3() {
label3.textColor = UIColor.purpleColor()
}
private func styleLabel4() {
label4.textAlignment = .Center
label4.textColor = UIColor.grayColor()
}
private func styleLabel5() {
label5.backgroundColor = UIColor.greenColor()
label5.font = UIFont.boldSystemFontOfSize(28)
}
private func styleLabel6() {
label6.lineBreakMode = .ByClipping
label6.numberOfLines = 0
}
private func styleButton1() {
button1.layer.borderWidth = 1
button1.layer.borderColor = UIColor.blueColor().CGColor
}
private func styleView1() {
view1.backgroundColor = UIColor.cyanColor()
}
}
当我们不需要对 view controller 中的这些控件进行引用时,可以移除它们。或者把它们留着也行,取决于你的需求。
某些时候你需要调用 style()
方法,所以最后你只需要在 view controller 与该对象间建立 outlet,并在 viewDidLoad
中调用 style()
。
最后 view controller 看起来像下面这样。
class ManyLabelsViewController: UIViewController {
// 保留那些你需要调用的控件...
@IBOutlet private var style: ManyLabelsViewControllerStyle!
override func viewDidLoad() {
super.viewDidLoad()
style.style()
// 一些其他代码...
}
}
你也可以在 样式 对象中使用 didSet,在 outlets 设置完成后让该对象来配置。
class ManyLabelsViewControllerStyle: NSObject {
@IBOutlet private weak var label1: UILabel! {
didSet {
label1.textColor = UIColor.redColor()
label1.font = UIFont.systemFontOfSize(20)
label1.backgroundColor = UIColor.blueColor()
}
}
@IBOutlet private weak var label2: UILabel! {
didSet {
label2.layer.borderColor = UIColor.yellowColor().CGColor
label2.layer.borderWidth = 1
label2.backgroundColor = UIColor.blueColor()
label2.clipsToBounds = true
}
}
@IBOutlet private weak var label3: UILabel! {
didSet {
label3.textColor = UIColor.purpleColor()
}
}
@IBOutlet private weak var label4: UILabel! {
didSet {
label4.textAlignment = .Center
label4.textColor = UIColor.grayColor()
}
}
@IBOutlet private weak var label5: UILabel! {
didSet {
label5.backgroundColor = UIColor.greenColor()
label5.font = UIFont.boldSystemFontOfSize(28)
}
}
@IBOutlet private weak var label6: UILabel! {
didSet {
label6.lineBreakMode = .ByClipping
label6.numberOfLines = 0
}
}
@IBOutlet private weak var button1: UIButton! {
didSet {
button1.layer.borderWidth = 1
button1.layer.borderColor = UIColor.blueColor().CGColor
}
}
@IBOutlet private weak var view1: UIView! {
didSet {
view1.backgroundColor = UIColor.cyanColor()
}
}
}
你的 view controller 看起来会像下面这样:
class ManyLabelsViewController: UIViewController {
// 保留那些你需要调用的控件...
@IBOutlet private var style: ManyLabelsViewControllerStyle!
// 不需要调用其他方法。
}
文章原链接404了 orz
http://szulctomasz.com/ios-a-beautiful-way-of-styling-iboutlets-in-swift/