7

[Android开发学iOS系列] TableView展现一个list - 圣骑士wind

 2 years ago
source link: https://www.cnblogs.com/mengdd/p/iOS-tableview-basics.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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里.
再分别实现UITableViewDelegateUITableViewDataSource, 这里写在extension里, 拆分完之后set给tableView:

tableView.delegate = selftableView.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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK