Swift 簡潔之道(上)

作者: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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容