顯示廣告
隱藏 ✕
看板 KnucklesNote
作者 Knuckles (站長 那克斯)
標題 [Xcode][Swift3] 使用 Table View 產生列表頁
時間 2017-03-01 Wed. 08:15:47


延續上一篇 [Xcode][Swift3] 使用 Swift3 開新專案 - KnucklesNote板 - Disp BBS

使用 Sigle View Application 建立一個新專案之後
我們想要將初始頁面改為一個 Table View
所以要刪掉預設的 View Controller,改成 Table View Controller

先點一下 storyboard 中的 View Controller 後按 Delete 刪除
再點一下相應的程式檔 ViewController.swift 後按 Delete,選「Move to Trash」刪除
[圖]


回到 storyboard
從右下的 Object library 拉一個 Navigation Controller 進來
[圖]


Navigation Controller 後面就會自動附帶一個 Table View Controller
Navigation Controller 後面加上的頁面會在上方產生一條固定住的導覽列 Navigation Bar

此時會冒出兩個警告訊息,點一下三角型的警告圖示
[圖]


第一個警告是說 Table View 中的 Cell 必需要設定 reuse identifier

點一下左邊 Document Outline 的「Table View Cell」
(或是點圖中的 Prototype Cells)
然後在右邊的 Attributes inspector (屬性檢視器)
在 Indentifier 輸入「HotTextCell」,之後會在程式裡用到
[圖]


第二個警告是說 Navigation Controller 沒有進入點

點一下 Navigation Controller,在右邊的屬性檢視器,
將「Is Initial View Controller」打勾
Navigation Controller 的左邊就會出現一個進入點的箭頭,
代表程式一開始會先從這個頁面開始顯示
[圖]


這樣兩個警告就消失了


接著修改 Table View 頁面上方的 Navigation Bar 要顯示的文字
因為 Table View Controller 是附屬在 Navigation Controller 之後
所以會有一個 Navigation item,在左邊的 Document Outline 點一下後
在右邊的屬性檢視器將 Title 改為「熱門文章」
Back Button 改為「回列表」
[圖]


Back Button 就是點選列表進到另一頁後,在左上角的按鈕要顯示的文字
[圖]



Table View 中每一列的元件叫做 Cell
要修改 Cell 的樣式,可以在屬性檢視器將 Style 改為內建的樣式「Subtitle」
[圖]

可以看到 Cell 中自動出現了兩個 Label


在 Table View 中顯示動態資料

要在 Table View 裡填入資料的話
要新增一個自訂的 Table View Controller 類別程式檔

點「File」/「New」/「File...」(或 command+n)
[圖]


選 iOS 的「Cocoa Touch Class」,點「Next」
[圖]


Class 輸入類別名稱「HotTextViewController」
Subclass of 輸入要繼承的類別「UITableViewController」
語言選「Swift」,點「Next」
[圖]


選擇檔案的儲存位置,預設就是專案的資料夾,點「Create」
就產生了一個繼承自 UITableViewController 的類別 HotTextViewController
[圖]


產生類別程式檔後要記得在 storyboard 設定自訂類別
到 storyboard 點一下 Table View Controller
在右邊的 Identity inspector 將 Class 設定為 HotTextViewController
[圖]



修改 HotTextViewController.swift

將自動產生的兩個成員函數改為
    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return 5
    }
第一個函數是設定 Table View 有幾個 Section,
將 return 0 改為 return 1 即可

第二個函數是設定每個 section 各有幾個 row
先測試看看,將 return 0 改為 return 5,直接設定為 5 個

將第一個被註解掉的函數取消註解,並改為
    // 1.
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // 2.
        let cell = tableView.dequeueReusableCell(withIdentifier: "HotTextCell", for: indexPath)

        // Configure the cell...
        // 3.
        cell.textLabel?.text = "這是第 \(indexPath.row) 列"
        cell.detailTextLabel?.text = "測試文字"

        return cell
    }
1. 關於函數的輸入參數,有分為外部(External)參數名和內部(Local)參數名
   例如第二個輸入參數為 cellForRowAt indexPath: IndexPath
   cellForRowAt 是外部參數名,是在呼叫這個函數時要輸入的,
   例如要取得第0列的cell可使用 cell = tableView(tableView, cellForRowAt: 0)
   indexPath 是內部參數名,只能在函數定義的內容中使用

   外部變數名使用底線 _ 時,代表呼叫時可以不用輸入外部參數名

2. 將 "reuseIdentifier" 改成之前在 storyboard 設定的 "HotTextCell"

   這邊使用 dequeueReusableCell() 取得了一個可回收的 cell
   為了避免列數太多時記憶體不夠用,所以 Table View 只會顯示目前滑動範圍內的 cell
   滑動列表頁時會將滑出範圍外的 cell 回收,變成新出現的 cell 來使用

3. 設定 Cell 中兩個 Label 要顯示的文字
   主標題的文字中使用 \(indexPath.row) 在字串中使用函數的局部參數名,
   取得目前這是第幾個 row

   關於 cell.textLabel?.text = "..." 中,textLabel 後面的問號
   意思是當問號前的值是 nil 時,問號後的程式就不執行了,並傳出 nil 傳
   用來避免 cell.textLabel 不存在時,卻呼叫了 .text 造成程式錯誤


執行看看
[圖]

可以顯示 5 個 row,並顯示各自是第幾個 row


使用自訂的 cell 樣式

前面我們在 storyboard 將 cell 的樣式設為內建的 Subtitle
所以取得的 cell 會有兩個成員變數 textLabel 與 detailTextLabel 可以設定
如果想要使用自訂的成員變數的話,要改寫 Table View Cell 類別的程式檔

按 command+n 新增 Cocoa Touch Class
Class: HotTextCell
Subclas of: UITableViewCell
[圖]

新增一個繼承自 UITableViewCell 的類別 HotTextCell

Note: 自訂類別的名稱應該取為「TableViewCell」比較好
      因為這個自訂類別的功用只有加上成員變數而已,
      之後加上其他的 TableView 時可以共用這個 Cell 類別

打開 HotTextCell.swift
在 class HotTextCell: UITableViewCell { 這行下面加上
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var descLabel: UILabel!
    @IBOutlet weak var thumbImageView: UIImageView!

建立了三個成員變數 titleLabel, descLabel, thumbImageView
用來顯示兩個 UILabel 與一個 UIImageView
前面加上 @IBOutlet 代表這是要用來連結 storyboard 上面的元件用的

變數的型態後面加了問號或驚嘆號時,代表這個變數可以是 nil 值 (Optional)
使用驚嘆號代表變數被賦值後就不會再變成 nil 值了


到 storyboard 點一下 Table View Cell,
在 Identity inspector 設定 Class 為剛剛新增的程式檔 HotTextCell
[圖]


點一下 Table View 後在右邊的 Size inspector (尺寸檢視器)
將 Row Height 從 44 改為 100
[圖]

可以看到 Cell 的高度變大了

注意在使用動態 Table View 時,設定 Cell 的高度沒有用
要設定 Table View 的高度才行

在 Table View Cell 的屬性檢視器,將 Style 改回 Custom
[圖]


從右下角的 Object library 拉一個 ImageView 進來
在尺寸設定 X: 0, Y: 0, Width: 100, Height: 100
[圖]


屬性檢視器的 Content Mode 選「Aspect Fill」,
Drawing 的「Clip To Bounds」打勾,
這樣會將圖片等比例縮小到寬或高為100,然後裁掉超出範圍的部份
[圖]


再拉兩個 Label 進來
第一個 Label 的屬性檢視器
Text: Plain title, Color: 藍色, Font: System 16.0, Lines: 2
Autoshrink: Minimum Font Size 14 (文字太多時自動將文字縮小,最小至14)
尺寸設定 X: 108, Y: 5, Width: 259, Height 38
第二個 Label 的屬性檢視器
Text: Plain title, Color: 黑色, Font: System 14.0, Lines: 3
尺寸設定 X: 108, Y: 45, Width: 259, Height 52
[圖]

(顯示的可能會跟上面的圖不太一樣,因為設定值有再改過)

接著要將這三個元件連結之前在類別中新增的三個成員變數

點一下 Table View Cell,在右邊的 Connection inspector (連結檢視器)
可以在 Outlets 看到我們之前新增的三個成員變數
[圖]


將三個成員變數右邊的圈圈拉到圖中對應的位置
[圖]

即完成類別的成員變數與 storyboard 元件的連結


加入一張要用來顯示的圖檔 displogo120.png
打開左邊的 Assets.xcassets,從 Finder 將圖片拉進來
[圖]



打開 HotTextViewController.swift
修改成員函數 tableView(_:cellForRowAt:)
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // 1.
        let cell = tableView.dequeueReusableCell(withIdentifier: "HotTextCell", for: indexPath) as! HotTextCell

        // Configure the cell...
        // 2.
        cell.titleLabel?.text = "這是第 \(indexPath.row) 列"
        cell.descLabel?.text = "測試文字 測試文字 測試文字 測試文字 測試文字 測試文字 測試文字 測試文字 測試文字 測試文字 "
        cell.thumbImageView?.image = UIImage(named: "displogo120")

        return cell
    }

1. 後面加上 as! HotTextCell 將取得的 TextViewCell 向下轉型為子類別 HotTextCell
   加驚嘆號代表這是一個確定可以成功的轉型

2. 設定 HotTextCell 類別的三個成員變數


執行看看
[圖]


圖片和文字可以正常顯示了,
但是在橫置,或是用其他尺寸的手機時版面不會自動調整
[圖]



設定 Auto Layout

打開 storyboard
點一下 Title Label 後,點右下角的「Add New Constraints」按鈕
[圖]


點一下上、左、右三個方向的虛線,讓他變實線
[圖]


左方向的點下拉選單,選與 Content View 的間距,而不是 Image View
[圖]


將 Height 打勾,然後點「Add 4 Constraints」
[圖]

加上這四個 Constraints 的意思就是說
我要固定住 Title Label 的上、左、右與 Content View 的間距
以及固定 Title Label 的高度,而寬度是不固定的
所以當 Content View 變寬時,Title Label 就會跟著變寬了

雖然 Content View 的高度是不會變的,
但是只要設定了左右的 Constraints,就會出現缺少上下 Constraints 的警告
所以四個方向都得要設定才行

接下來加上 Desc Label 的四個 Constraints
左邊一樣要選擇與 Content View 的間距,上方是與 Title Label 的間距
[圖]


如果 Constraints 設定錯誤了,可以點右下角的「Resolve Auto Layout Issues」
然後選 Selected Views 的「Clear Constraints」
就可以將 Constraints 清掉重新設定了

如果元件的尺寸設定和 Constraints 的設定不相符時,會出現橘色的線
可以點「Resolve Auto Layout Issues」的「Update Constraint Constants」
更新 Constraints 的設定值

或是點「Update Frames」按鈕,將元件的尺寸設定更新為 Constraints 的設定值
[圖]


執行看看,在橫置的時候會自動符合寬度了
[圖]



分隔線設定

Table View 的分隔線預設左邊有15點的間距
要取消間距的話,在 Table View Cell 的屬性檢視器
Separator 選「Custom Insets」,Left 改為 0
[圖]


執行結果
[圖]



要讀取網站內容顯示在列表中的話,參考下一篇
[Xcode][Swift3] 使用 Alamofire 存取網站資料 - KnucklesNote板 - Disp BBS


參考
Ray Wenderlich: Storyboards Tutorial in iOS 9: Part 1



--
※ 作者: Knuckles 時間: 2017-03-01 08:15:47
※ 編輯: Knuckles 時間: 2017-04-16 15:48:34
※ 看板: KnucklesNote 文章推薦值: 0 目前人氣: 0 累積人氣: 1702 
分享網址: 複製 已複製
r)回覆 e)編輯 d)刪除 M)收藏 ^x)轉錄 同主題: =)首篇 [)上篇 ])下篇