你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> Auto Layout 使用心得

Auto Layout 使用心得

編輯:IOS開發基礎

Auto Layout 使用心得(一)--初體驗

本系列文章將從一個慢慢摸索中的新手的角度介紹 Auto Layout,講述我在這兩個月的學習中對它一點一滴的感受,最終目的是讓大家在閱讀完之後能夠自己上手使用,並完成絕大多數簡單的布局約束。

此系列文章代碼倉庫在 https://github.com/johnlui/AutoLayout ,有不明白的地方可以參考我的 Auto Layout 設置哦,下載到本地打開就可以了。

簡介

Auto Layout 是蘋果在 Xcode 5 (iOS 6) 中新引入的布局方式,旨在解決 3.5 寸和 4 寸屏幕的適配問題。屏幕適配工作在 iPhone 6 及 plus 發布以後變得更加重要,而且以往的“笨辦法”的工作量大幅增加,所以很多人開始學習使用 Auto Layout 技術。

初體驗

0. 開發環境

本系列文章的開發環境為:

  • OS X 10.10.2

  • Xcode Version 6.2 (6C131e)

1. 新建應用

新建一個 Single View Application,命名為 AutoLayout,如下:

1.jpg

點擊選中 Main.storyboard,右側內容如下:

2.jpg

1、2 兩個按鈕將會在未來的開發中產生巨大的作用,他們將擁有本系列文章的全局名稱:按鈕1,按鈕2。請先記下他們的位置。

2. 直接上手,開始使用

這也是我對學習新的軟件編程技術的基本學習方法:有一個具體客觀驅動的目標,例如做一個真正要給客戶用的軟件,而不是“為了學習新技術提高自己”這類偽目標。

讓我們直接上手:繪制一個距離左右邊都有一定距離、固定高度、垂直居中的按鈕,叫“Swift on iOS”。

1. 第一步,從右側拖過來一個按鈕,置於頁面最中間。會有參考線出現,這一步很容易:

3.jpg

2. 選中這個 button,將按鈕背景色和前景色進行如下設置:  

4.jpg

3. 將按鈕左側邊界往左拖動直到自動吸附,留下一定的距離。右側進行同樣操作:  

5.jpg

4. 選中這個 button,修改文字為 Swift on iOS:  

6.jpg

5. 選中這個 button,點擊 按鈕2 ,選擇這一項:  

7.jpg

這時候 button 周圍會出現一些藍色的線條,這些就是 Auto Layout 的約束項。

3. 大功告成,查看效果

3.5:  

8.jpg

4:  

9.jpg

4.7:  

10.jpg

5.5:  

11.jpg

4. 分析

選中這個 button,在右側查看自動生成的約束項:  

12.jpg

只有三項,這三項的意思分別是:和父視圖縱向居中對齊、右側和父視圖對齊、左側和父視圖對齊。

我們很容易就能理解這樣可以定位一個按鈕,但是總感覺少了點什麼。實際上這三個自動生成的約束項並不能描述一個 button 的位置,因為少了一個關鍵的屬性:button 的高度。以後我們會詳細地討論。

5. 核心思想

本質分析

Auto Layout 的本質是依靠 某幾項約束條件 來達到對某一個元素的定位。我們可以在某個地方只使用一個約束,以達到一個小目的,例如防止內容遮蓋、防止邊界溢出等。但我的最佳實踐證明,如果把頁面上每一個元素的位置都用 Auto Layout 進行 “嚴格約束” 的話,那麼 Auto Layout 可以幫我們省去非常多的計算 frame 的代碼。

“嚴格約束” 是什麼?

簡單來說,嚴格約束就是對某一個元素的絕對定位,讓它在任一屏幕尺寸下都有著唯一的位置。這裡的絕對定位不是定死的位置,而是對一個元素 完善的約束條件。

讓我們看圖說話:

13.png

  1. 我們要在一個直角坐標系裡描述一個矩形。

  2. 那麼只需要指定這個矩形的位置和大小。

  3. 那麼只要給出上圖中的四個值即可:到左邊界的距離,到上邊界的距離,寬度,高度。

  4. 這四個約束是最簡單的情況。在對一個元素進行嚴格約束時,請直接在腦中構建這個元素,並且加上幾條約束條件,如果他無法縮放和動彈,那麼嚴格約束就是成功的!

  5. 必須牢記,使用 Auto Layout 時最重要的是:對頁面上每一個元素都進行嚴格約束,不嚴格的約束是萬惡之源。

Auto Layout 使用心得(二)--實現三等分

此系列文章代碼倉庫在 https://github.com/johnlui/AutoLayout ,有不明白的地方可以參考我的 Auto Layout 設置哦,下載到本地打開就可以了。
准備

上一篇文章中,我們共同進行了 Auto Layout 的初體驗,在本篇我們將一起嘗試用 Auto Layout 實現三等分。

Auto Layout 的本質原理

Auto Layout 的本質是用一些約束條件對元素進行約束,從而讓他們顯示在我們想讓他們顯示的地方。

約束主要分為以下幾種(歡迎補充):

  1. 相對於父 view 的約束。如:距離上邊距 10,左邊距 10。

  2. 相對於前一個元素的約束。如:距離上一個元素 20,距離左邊的元素 5 等。

  3. 對齊類約束。如:跟父 view 左對齊,跟上一個元素居中對齊等。

  4. 相等約束。如:跟父 view 等寬。

三等分設計思路

許多人剛開始接觸 Auto Layout,可能會以為它只能實現上面的1、2功能,其實後面3、4兩個功能才是強大、特別的地方。接下來我們將嘗試設計橫向三等分:

  1. 第一個元素距離左邊一定距離。

  2. 最後一個元素距離右邊一定距離。

  3. 三者高度恆定,寬度相等。

  4. 1和2、2和3的橫向間距固定。

干貨,實現過程的動圖:

14.gif

運行結果

4 寸:

15.jpg

4.7 寸:

16.jpg

縱向三等分實現方式類似,大家可以自己嘗試一下哦~

Auto Layout 使用心得(三)—— 自定義 cell 並使用 Auto Layout

此系列文章代碼倉庫在 https://github.com/johnlui/AutoLayout ,有不明白的地方可以參考我的 Auto Layout 設置哦,下載到本地打開就可以了。
簡介

本篇中我們將嘗試自定義一個 UITableViewCell,並使用 Auto Layout 對其進行約束。

自定義 cell 基礎

在前面的項目中,我們采用 StoryBoard 來組織頁面,StoryBoard 可以視為許多個 xib 的集合,所以我們可以得到兩個信息:

  1. 這個項目通過初始化主 StoryBoard 文件來展現 APP,而 UIViewController 類文件是通過 StoryBoard 文件的綁定來初始化並完成功能的。

  2. 我們可以創建新的 StoryBoard 文件或者新的 xib 文件來構造 UI,然後動態地加載進頁面。

創建文件

我們可以一次性創建 xib 文件和類的代碼文件。

新建 Cocoa Touch Class:

17.jpg

設置和下圖相同即可:

18.jpg

檢查成果

19.jpg

分別選中上圖中的 1、2 兩處,檢查 3 處是否已經自動綁定為 firstTableViewCell,如果沒有綁定,請先檢查選中的元素確實是 2,然後手動綁定即可。

完成綁定工作

切換一頁,如下圖進行 Identifier 設置:

20.jpg

新建 Table View Controller 頁面

新建一個 Table View Controller 頁面,並把我們之前創建的 Swift on iOS 那個按鈕的點擊事件綁定過去,我們得到:

21.jpg

然後創建一個名為 firstTableViewController 的 UITableViewController 類,創建流程跟前面基本一致。不要創建 xib。然後選中 StoryBoard 中的 Table View Controller(選中之後有藍色邊框包裹),在右側對它和 firstTableViewController 類進行綁定:

22.jpg

調用自定義 cell

修改 firstTableViewController 類中的有效代碼如下:

import UIKit
class firstTableViewController: UITableViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        var nib = UINib(nibName: "firstTableViewCell", bundle: nil)
        self.tableView.registerNib(nib, forCellReuseIdentifier: "firstTableViewCell")
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    // MARK: - Table view data source
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("firstTableViewCell", forIndexPath: indexPath) as firstTableViewCell
        cell.textLabel?.text = indexPath.row.description
        return cell
    }
}

viewDidLoad() 中添加的兩行代碼是載入 xib 的操作。最下面的三個 func 分別是定義:

  1. self.tableView 中有多少個 section

  2. 每個 section 中分別有多少個條目

  3. 實例化每個條目,提供內容

如果你得到以下頁面,說明你調用自定義 cell 成功了!

23.jpg

給自定義 cell 添加元素並使用 Auto Layout 約束

首先向 Images.xcassets 中隨意加入一張圖片。

然後在左側文件樹中選中 firstTableViewCell.xib,從右側組件庫中拖進去一個 Image View,並且在右側將其尺寸設置如下圖右側:

24.jpg

給 ImageView 添加約束:

25.jpg

選中該 ImageView(左箭頭所示),點擊自動 Auto Layout(右箭頭所示),即可。

給 ImageView 設置圖片:

26.jpg

再從右側組件庫中拖入一個 UILabel,吸附到最右側,垂直居中,為其添加自動約束,這一步不再贅述。

在 firstTableViewCell 類中綁定 xib 中拖進去的元素

選中 firstTableViewCell.xib,切換到雙視圖,直接進行拖動綁定:

27.jpg

綁定完成!

約束 cell 的高度

在 firstTableViewController 中添加以下方法:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return 50
}

給自定義的 UILabel 添加內容

修改 firstTableViewController 中以下函數為:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("firstTableViewCell", forIndexPath: indexPath) as firstTableViewCell
    cell.firstLabel.text = indexPath.row.description
    return cell
}

查看結果

4.0 寸:

28.jpg

4.7 寸:

29.jpg

如果你得到以上結果,那麼恭喜你自定義 cell 並使用 Auto Layout 成功!

Auto Layout 使用心得(四)—— 22 行代碼實現拖動回彈

此系列文章代碼倉庫在 https://github.com/johnlui/AutoLayout ,有不明白的地方可以參考我的 Auto Layout 設置哦,下載到本地打開就可以了。
簡介

本文中,我們將一起使用 UIPanGestureRecognizer 和 Auto Layout,通過 22 行代碼實現拖動回彈效果。

搭建界面

刪除首頁中間的按鈕,添加一個 View ,設置一種背景色便於辨認,然後對其進行絕對約束:

30.jpg

拖動一個 UIPanGestureRecognizer 到該 View 上:

31.jpg

界面搭建完成。

屬性綁定

切換到雙向視圖,分別右鍵拖動 UIPanGestureRecognizer 和該 View 的 Top Space 的 Auto Layout 屬性到 ViewController 中綁定:

32.jpg

然後將 UIPanGestureRecognizer 右鍵拖動綁定:

33.jpg

編寫代碼

class ViewController: UIViewController {
    
    var middleViewTopSpaceLayoutConstant: CGFloat!
    var middleViewOriginY: CGFloat!
    
    @IBOutlet weak var middleView: UIView!
    @IBOutlet weak var middleViewTopSpaceLayout: NSLayoutConstraint!
    @IBOutlet var panGesture: UIPanGestureRecognizer!
    override func viewDidLoad() {
        super.viewDidLoad()
        
        panGesture.addTarget(self, action: Selector("pan"))
        middleViewTopSpaceLayoutConstant = middleViewTopSpaceLayout.constant
        middleViewOriginY = middleView.frame.origin.y
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func pan() {
        if panGesture.state == UIGestureRecognizerState.Ended {
            UIView.animateWithDuration(0.4, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
                self.middleView.frame.origin.y = self.middleViewOriginY
                }, completion: { (success) -> Void in
                    if success {
                        self.middleViewTopSpaceLayout.constant = self.middleViewTopSpaceLayoutConstant
                    }
            })
            return
        }
        let y = panGesture.translationInView(self.view).y
        middleViewTopSpaceLayout.constant = middleViewTopSpaceLayoutConstant + y
    }
}

查看效果

34.gif

22 行代碼,拖動回彈效果完成!

Auto Layout 使用心得(五)--根據文字、圖片自動計算 UITableViewCell 高度

此系列文章代碼倉庫在 https://github.com/johnlui/AutoLayout ,有不明白的地方可以參考我的 Auto Layout 設置哦,下載到本地打開就可以了。
簡介

本文中,我們將一起使用 Auto Layout 技術,讓 UITableViewCell 的高度隨其內部的 UILabel 和 UIImageView 的內容自動變化。

搭建界面

恢復之前刪除的按鈕

放置一個按鈕,恢復到 firstTableViewController 的連接:

34.jpg

別忘了添加約束讓他居中哦。

修改 firstTableViewCell

將 firstTableViewCell 的尺寸設置為 600 * 81,將 logo 的尺寸設置為 80 * 80。將 logo 的約束修改為如下圖所示:

35.jpg

修改 label 的尺寸和位置,添加約束如下圖:

36.jpg

給 ViewController 增加 UINavigationController 嵌套

為了便於返回。操作如下圖:

37.jpg

查看結果

38.jpg

根據 label 自動計算 firstTableViewCell 高度

選中 label,設置 lines 行數為 0,表示不限長度自動折行:

42.jpg

修改 label 的文字內容讓其超出一行:

import UIKit
class firstTableViewController: UITableViewController {
    
    var labelArray = Array() // 用於存儲 label 文字內容
    override func viewDidLoad() {
        super.viewDidLoad()
        var nib = UINib(nibName: "firstTableViewCell", bundle: nil)
        self.tableView.registerNib(nib, forCellReuseIdentifier: "firstTableViewCell")
        
        // 循環生成 label 文字內容
        for i in 1...10 {
            var text = ""
            for j in 1...i {
                text += "Auto Layout"
            }
            labelArray.append(text)
        }
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    // MARK: - Table view data source
    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 50
    }
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return labelArray.count
    }
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("firstTableViewCell", forIndexPath: indexPath) as! firstTableViewCell
        cell.firstLabel.text = labelArray[indexPath.row]
        return cell
    }
}

現在到了最關鍵的時刻,驅動 UITableViewCell 適應 Label 內容:

1. 使用 estimatedHeightForRowAtIndexPath 替代 heightForRowAtIndexPath

estimatedHeightForRowAtIndexPath 是 iOS 7 推出的新 API。如果列表行數有一萬行,那麼 heightForRowAtIndexPath 就會在列表顯示之前計算一萬次,而 estimatedHeightForRowAtIndexPath 只會計算當前屏幕中顯示著的幾行,會大大提高數據量很大時候的性能。

2. 新建一個 prototypeCell 成員變量以復用,並在 viewDidLoad 中初始化

class firstTableViewController: UITableViewController {
    
    var labelArray = Array() // 用於存儲 label 文字內容
    
    var prototypeCell: firstTableViewCell!
    override func viewDidLoad() {
        super.viewDidLoad()
        var nib = UINib(nibName: "firstTableViewCell", bundle: nil)
        self.tableView.registerNib(nib, forCellReuseIdentifier: "firstTableViewCell")
        
        // 初始化 prototypeCell 以便復用
        prototypeCell = tableView.dequeueReusableCellWithIdentifier("firstTableViewCell") as! firstTableViewCell
        
......

3. 計算出高度

override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    let cell = prototypeCell
    cell.firstLabel.text = labelArray[indexPath.row]
    return cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1
}

4. 查看效果

40.jpg

超級大坑

上面讓 firstTableViewCell 根據 label 自動計算高度的過程中,有一個超級大坑:如果給左側 UIImageView 賦的圖片較大(大於 80px),將看到如下奇怪的結果:

41.jpg

這只是因為圖片把 UITableViewCell 撐大了,並不是我們的計算沒有效果。

解決大坑:進攻是最好的防守!根據圖片自動計算 firstTableViewCell 高度

首先,把圖片的渲染模式改成 Aspect Fit:

42.jpg

給 Images.xcassets 增加三張圖片,命名為 0、1、2,尺寸從小到大:

43.jpg

給 cellForRowAtIndexPath 增加代碼:

if indexPath.row < 3 {
    cell.logoImageView.image = UIImage(named: indexPath.row.description)
}

查看效果:

44.jpg

前兩個 cell 看起來比較正常,第三個為什麼多出了那麼多空白?這就是使用 Auto Layout 限制圖片寬度為 80px 的原生問題:寬度雖然限制了,高度卻依然是原圖的高度。解決辦法也很簡單:如果圖片寬度大於 80px,就重繪一張 80px 寬度的圖片填充進去。

新建一個 Group(虛擬文件夾),叫 Extensions,並在其內部新建 UIImage.swift 文件,內容如下:

import UIKit
extension UIImage {
    func resizeToSize(size: CGSize) -> UIImage {
        UIGraphicsBeginImageContext(size)
        self.drawInRect(CGRectMake(0, 0, size.width, size.height))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return newImage
    }
}

給 UIImage 類擴展了一個名為 resizeToSize 的方法,返回一個按照要求的大小重繪過的 UIImage 對象。修改 cellForRowAtIndexPath 的代碼為:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("firstTableViewCell", forIndexPath: indexPath) as! firstTableViewCell
    cell.firstLabel.text = labelArray[indexPath.row]
    
    if indexPath.row < 3 {
        var image = UIImage(named: indexPath.row.description)!
        if image.size.width > 80 {
            image = image.resizeToSize(CGSizeMake(80, image.size.height * (80 / image.size.width)))
        }
        cell.logoImageView.image = image
    }
    return cell
}

搞定!

查看效果

46.gif

從上圖可以看出,cell 已經可以根據圖片和文字中比較高的一個完全自適應。

致謝

感謝 《動態計算UITableViewCell高度詳解》,給我提供了許多基礎知識和靈感。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved