swift 3:如何做出可展開的table view (Expandable Table View)

  1. 開啟一個新的xcode專案,在Main.storyboard的viewController加入UITableView,及設定layout、設定tableView的delegate、dataSource,最後將tableView拉入viewController的IBoutlet

在Table View屬性的Prototype Cells中輸入cell數為2,並將下方cell的style選為basic

最後先點選View Controller 接著點擊上方工具列Editor > Embed In > Navigation Controller

點擊位於View Controller 上方之Navigation Bar ,於右方屬性輸入其Title

2. 開啟一個swift的檔案(這裡將檔案命名為section)

3. 在section 中,先決定tableView 中,每個section的基本結構:

struct section {
var sectionClass: String!
var name: [String]!
var expanded: Bool!
}

再給予建構式

init(sectionClass: String, name: [String], expanded: Bool) {
self.sectionClass = sectionClass
self.name = name
self.expanded = expanded
}

4. 接著再開啟一個Cocoa Touch Class的檔案,subClass為UITableViewHeaderFooterView(這裡將檔案命名為expandableHeaderView)

5. 在expandableHeaderView.swift中,先建立一個協議(protocol)

protocol expandableHeaderViewDelegate {
func toggleSection(header: expandableHeaderView, section: Int)
}

接著在class中宣告變數及建構式

var delegate: expandableHeaderViewDelegate?
var section: Int!
func customInit(title: String, section: Int, delegate: expandableHeaderViewDelegate){
self.textLabel?.text = title
self.section = section
self.delegate = delegate
}

接著決定header section的樣子,覆蓋 layoutSubviews()這個函式

override func layoutSubviews() {
super.layoutSubviews()
self.textLabel?.textColor = UIColor.black
self.contentView.backgroundColor = UIColor.lightGray
}

最後復寫UITableViewHeaderFooterView之建構式,讓其加上點擊之手勢

override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(clickSecionHeader)))
}
required init?(coder aDecoder: NSCoder) {
fatalError(“init(coder:) has not been implemented”)
}
@objc func clickSecionHeader(gesture: UITapGestureRecognizer){
let cell = gesture.view as! expandableHeaderView
delegate?.toggleSection(header: self, section: cell.section)
}

6. 回到ViewController.swift中,擴展(extension)ViewController,使其繼承UITableViewDelegate, UITableViewDataSource,並加入delegate必須呼叫之函式

7. 宣告一個變數,並使其為section之結構

8. 呼叫UITableViewDelegate之函式,定義tableView之結構

func numberOfSections(in tableView: UITableView) -> Int {
// selecion 種類個數
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// 某種類中 物件個數
return sections[section].name.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
// Section的header的高度
let height = self.view.frame.height / 10
return height
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// Section中 row的高度
// 若expanded為false,row高度為0
let height = self.view.frame.height / 10
if (sections[indexPath.section].expanded) {
return height
}else{
return 0
}
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
// 最後一個row與下一個section的間距
return 2
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
// 宣告每一個section header的view
let header = expandableHeaderView()
header.customInit(title: sections[section].sectionClass, section: section, delegate: self)
return header
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 宣告每一個row
let cell = tableView.dequeueReusableCell(withIdentifier: “cell”)!
cell.textLabel?.text = sections[indexPath.section].name[indexPath.row]
return cell
}

9. 回到Main.storyboard,在第二個Table View Cell 給予其Identifier: cell

10. 在ViewController.swift中,擴展(extension)ViewController,使其繼承expandableHeaderViewDelegate,並呼叫函式toggleSection( )

當點擊header後,要讓row顯示出來,故expanded 要從false轉為true

sections[section].expanded = !(sections[section].expanded)

另外也要一一更新row之屬性

for i in 0 ..< sections[section].name.count {
tableView.reloadRows(at: [IndexPath(row: i, section: section)], with: .automatic)
}

最後加入tableView開始及結束更新之函式

tableView.beginUpdates()
tableView.endUpdates()

11. 執行程式即可發現已經完成可以展開之table view

備註:此文章為自己去網路上學習swift之記錄,原文影片在這:

本人只是將學習過程記錄下來供需要的人參考用。