TableView 基礎 本文講講TableView的基本使用. 順便介紹一下delegation. TableView用來做什麼 TableView用來展示一個很長的list. 和Android中的RecyclerView不同, iOS中的TableView只能是豎直方向的list. 如何寫一個最 ...
TableView 基礎
本文講講TableView的基本使用.
順便介紹一下delegation.
TableView用來做什麼
TableView用來展示一個很長的list.
和Android中的RecyclerView不同, iOS中的TableView只能是豎直方向的list.
如何寫一個最簡單的TableView
一個最簡單的TableViewController看起來像這樣:
class ViewController: UITableViewController {
var data: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// loadData()
print(data)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath)
cell.textLabel?.text = data[indexPath.row]
return cell
}
}
這裡data是想展示的數據類型, 可以hardcode一些數據.
這麼簡單是因為這個ViewController繼承了UITableViewController
, 並且cell的部分使用了storyboard.
這裡需要用dequeueReusableCell
方法, 是為了cell的復用, 因為list內容很多的時候cell view是可以迴圈使用的. (很像Android里的RecyclerView).
UITableViewController
的簽名是這樣:
open class UITableViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
它為我們做了以下三件事:
- 設置view為一個
UITableView
. - 設置
delegate=self
. - 設置
dataSource=self
.
這種方式的局限性在於第一點, 它的根view是一個TableView, 如果我們的需求比較複雜, 不僅僅是一個demo, 那麼可能需要組合View.
拆解版TableView
我們也可以直接繼承UIViewController
類, 然後自己動手做上面的幾條設置.
Delegate & DataSource
TableView有兩個重要的方面需要關註:
- UITableViewDelegate: 管理和用戶的交互, 比如選擇, 滑動手勢等. 沒有必須要實現的方法.
- UITableViewDataSource: 提供和管理數據, 包括了數據對應的cell或者header. 有兩個必須要實現的方法(如上面的代碼例子所示).
繼承UIViewController
繼承UIViewController而不是UITableViewController
之後, 需要自己寫一個tableView並加在view里.
再分別實現UITableViewDelegate
和UITableViewDataSource
, 這裡寫在extension里, 拆分完之後set給tableView:
tableView.delegate = self
tableView.dataSource = self
整體改造後代碼如下:
class ViewController: UIViewController {
var data: [String] = ["Hello", "World"]
private let tableView = UITableView()
override func loadView() {
view = UIView()
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(MyCell.self, forCellReuseIdentifier: "MyCell")
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewController: UITableViewDelegate {}
extension ViewController: UITableViewDataSource {
func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
data.count
}
func tableView(_: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as? MyCell {
cell.configure(with: data[indexPath.row])
return cell
}
return UITableViewCell()
}
}
自己的Cell class
這裡Cell也改用代碼類, 寫一個這樣的類:
class MyCell: UITableViewCell {
private let label = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: contentView.topAnchor),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
])
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure(with data: String) {
label.text = data
}
}
註意tableView註冊這個Cell類型:
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(MyCell.self, forCellReuseIdentifier: "MyCell")
}
補充知識: Delegation
上面的方法初看可能會非常怪. 這裡還涉及到了一個知識點是iOS中的delegate.
它存在的意義是為了拓展本身類的功能.
Apple自己的很多API就用了delegate protocol, 比如UIApplicationDelegate
, UITableViewDelegate
.
如果我們想自己定義一個:
protocol MyTypeDelegate: AnyObject {
func myType(_ myType: MyType,
shouldDoSomething argumentString: String) -> Bool
func myType(_ myType: MyType,
didAbortWithError error: Error)
func myTypeDidFinish(_ myType: MyType)
}
class MyType {
weak var delegate: MyTypeDelegate?
}
定義delegation的幾個原則:
- 方法名以被代理的類型開頭.
- 方法的第一個參數是被代理的對象.
References
作者: 聖騎士Wind出處: 博客園: 聖騎士Wind
Github: https://github.com/mengdd
微信公眾號: 聖騎士Wind