• [Android开发学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里.
    再分别实现UITableViewDelegateUITableViewDataSource, 这里写在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

  • 相关阅读:
    浮动练习-手机模块
    IQueryable和IEnumerable的区别
    Vue2-replace属性、编程式路由导航、缓存路由组件、两个新的生命周期钩子、路由守卫、路由器工作模式
    类 Unix 系统的文件目录结构
    调用DeleteLocalRef的正确姿势
    stm32之1602+DHT11+继电器
    正交序列扩频_解扩
    Openstack环境预设1
    CISP-PTE实操练习讲解
    linux fio磁盘性能测试工具使用指南和示例大全
  • 原文地址:https://www.cnblogs.com/mengdd/p/iOS-tableview-basics.html