UITableViewAgent:一个闭包搞定UITableView的代理实现

示例程序

要运行示例项目,克隆仓库,并首先从Example目录运行' pod install '。

安装与使用

UITableViewAgent可以通过CocoaPods获得。安装
在你的Podfile中添加以下代码:

pod 'UITableViewAgent'

运行条件:iOS 9.0+ (Swift 5+)

UITableViewAgent可以承担UITableViewDataSource和UITableDelegate的指责,让TableView的编码变得更加容易和充满乐趣。为什么要使用UITableViewAgent呢?请看下文。

使用UITableViewDataSource和UITableViewDelegate实现TableView数据呈现

让我们来看看传统的TableView编码:

  • 设置tableView的代理
tableView.dataSource = self
tableView.delegate = self    
  • 代理回调
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if section == 0 {
        return self.news.newslist?.count ?? 0
    } else if section == 1 {
        return 1
    } else {
        return 10
    }
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath.section == 0 {
        return UITableView.automaticDimension
    } else if indexPath.section == 1 {
        return 80.0
    } else {
        return 100.0
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.section == 0 {
        let cell = tableView.dequeueReusableCell(withIdentifier: "NewsListTableViewCell", for: IndexPath) as! NewsListTableViewCell
        cell.lblTitle.text = self.news.newslist![indexPath.row].title
        cell.lblSubTitle.text = self.news.newslist![indexPath.row].source
        return cell
    } else if indexPath.section == 1 {
        let cell = tableView.dequeueReusableCell(withIdentifier: "AppliancesTableViewCell", for: IndexPath) as! AppliancesTableViewCell.self
        cell.lblName.text = self.appliances!.name
        cell.lblColor.text = self.appliances!.color
        cell.lblPrice.text = "\(self.appliances!.price)"
        return cell
    } else {
        let cell = tableView.dequeueReusableCell(withIdentifier: "PersonTCell.self", for: IndexPath) as! PersonTCell
        cell.lblName.text = "人物 - \(indexPath.row)"
        return cell
    }
}

嗯...这里实现了一个多类型Cell和多种数据的TableView列表展示,这里没有列举出Header与Footer的复用,也没有列出Cell选中某行时的回调。
类似这样的代码实现有诸多的缺点

  • 代码量大:实现简单的功能需要大量代码,影响开发效率。
  • 灵活性差:配置数据和UI不够灵活,多个类的复用视图的处理需要繁琐判断,开发者需要自行计算索引值已经行数等不必要的数据。
  • 可阅读性差:为了遵守TableView的代理函数,形式上写入大量代码,却没有直观地凸显出数据和UI。

使用UITableViewAgent实现TableView数据呈现

定制Cell数据行

tableViewAgent = UITableViewAgent(tableView: tableView, display: UITableViewDisplay({ sections in
    sections.append(UITableViewSectionDisplay({ rows in
        for i in 0..<10 {
            rows.append(UITableViewRowDisplay(cellHeight: 60, cellType: UITableViewCell.self, reuseType: .anyClass) { tableView, indexPath, cell in
                cell.textLabel?.text = "row: _ \(i)"
            } didSelectRowAtIndexPath: {[weak self] tableView, indexPath, cell in
                guard let self = self else { return }
                let vc = TraditionalListViewController()
                self.navigationController?.pushViewController(vc, animated: true)
            })
        }
    }))
}))

只需要这里少许的代码即可实现10行行高为50.0像素点,类型为UITableViewCell的Cell,选中某一行时,通过其中didSelectRowAtIndexPath回调方法实现响应的操作。
当然,功能远远不只这么简单,若需要比较复杂的需求,它的优势将体现得更加明显。

比如:

  • Cell行数免计算灵活配置
  • 各行Cell高度灵活配置
  • 各行Cell类型与复用形式灵活配置
  • 各行Cell的数据展示灵活配置
  • 各行Cell点击响应事件的灵活配置
// 添加一行Cell展示动物信息
rows.append(UITableViewRowDisplay(cellHeight: 100, cellType: PersonTCell.self, reuseType: .nib) { tableView, indexPath, cell in
    cell.name.text = "Panda"
    cell.country.text = "China"
} didSelectRowAtIndexPath: { tableView, indexPath, cell  in
    // 选中动物Cell后回调
    tableView.deselectRow(at: indexPath, animated: true)
    print("Animal is selected:", tableView, indexPath, cell)
})

// 添加若干行Cell展示人物信息
for (i, person) in persons.enumerated() {
    rows.append(UITableViewRowDisplay(cellHeight: 60, cellType: PersonCell.self, reuseType: .anyClass) { tableView, indexPath, cell in
        cell.numberLabel.text = "Number is: \(i)"
        cell.nameLabel.text = person.name
        cell.genderLabel.text = person.gender
    }
}

// 添加电器Cell展示电视信息
rows.append(UITableViewRowDisplay(cellHeight: 120, cellType: AppliancesTableViewCell.self, reuseType: .nib) { tableView, indexPath, cell in
    cell.lblName.text = "TV"
} didSelectRowAtIndexPath: { tableView, indexPath, cell  in
// 选中电器Cell后回调
    tableView.deselectRow(at: indexPath, animated: true)
    print("This is a TV")
})

定制数据组

下列是展示一个新闻相关的组:

// 增加新闻section, header高度45,不允许自动行高(自动行高需要Cell的约束支持,即内容决定Cell高度),header复用形式为XIB,类型为NewsListTableHeaderView
sections.append(UITableViewSectionDisplay(headerHeight: 45.0, isAutoHeaderHeight: false, headerReuse:.nib(NewsListTableHeaderView.self, { tabelView, section, header in
// 给header设置标题
    header.lblName.text = "News Header"
}), { rows in
    // row.append(XXX)
    // row.append(XXX)
}, footerHeight: 50.0, isAutoFooterHeight: false, footerReuse: .anyClass(NewsListTableFooterView.self, { tableView, section, footer in
// footer高度50,不允许自动行高,header复用形式为anyClass,类型为NewsListTableFooterView,设置文本标签展示内容
    footer.lblDesc.text = "News Footer"
})))

header和footer的复用参数(headerHeight和footerReuse)可以设定类型如下:

  • .anyClass: 纯代码型视图,继承自UIView。
  • .nib: XIB型视图,继承自UITableHeaderFooterView。
  • .none: 不设定Header或Footer。

作者

Chen Bo(陈波), cba023@hotmail.com

证书

UITableViewAgent在MIT许可下可用。查看许可文件以获得更多信息。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335