您的位置:首页 > 移动开发 > Swift

RxSwift - UITableViewCell上按钮事件处理

2018-01-29 11:11 3047 查看
RxSwift与UITableView的使用,之前文章简单的实现了一下。今天主要是实现如何处理UITableViewCell上的按钮事件。以前我们通常会选择使用代理、闭包、通知这些方法中的一个方法,我个人喜欢闭包。但是现在已经开始使用RxSwift,所以一起来看看RxSwift中我们如何处理按钮事件。
UITableViewCell的内部事件
一般对于cell的点击,会触发其代理方法:  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// 处理cell的点击事件
}在Rx中,我们处理如下:
tableView.rx.modelSelected(ItemModel.self)
.subscribe(onNext: { value in
print(value)
}).disposed(by: disposeBag)
或者先获取点击的位置,然后在根据点击的位置获取数据
tableView.rx.itemSelected.asObservable()
.subscribe(onNext: { index in
print(index)
}).disposed(by: disposeBag)

由上可知对于cell的处理还是很简单的。

UITableViewCell上的按钮事件

比较好的方案就是闭包,前面也谈到了。那么我们如何使用Rx来处理呢?先看一个demo

自定义cell部分

该部分内容很简单,cell上添加了一个label和button,并进行布局import UIKit
import SnapKit
import RxSwift

class CustomTableViewCell: UITableViewCell {

private(set) var disposeBag = DisposeBag()

lazy var info: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 20)
return label
}()
lazy var button: UIButton = {
let btn = UIButton(type: .custom)
btn.setTitle("button", for: .normal)
btn.setTitleColor(UIColor.black, for: .normal)
btn.backgroundColor = UIColor.cyan
return btn
}()

override func prepareForReuse() {
super.prepareForReuse()
disposeBag = DisposeBag()
}

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
setupConstraints()
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func setupUI() {
addSubview(info)
addSubview(button)
}

private func setupConstraints() {
info.snp.makeConstraints { (make) in
make.left.top.right.equalToSuperview().inset(15)
}
button.snp.makeConstraints { (make) in
make.centerX.equalToSuperview()
make.top.equalTo(info.snp.bottom).offset(15)
make.size.equalTo(CGSize(width: 100, height: 50))
make.bottom.equalToSuperview().offset(-15)
}
}
}
这里有一个关键的地方:prepareForReuse()方法,在方法里面,每次重用cell的时候,我们会释放之前的disposeBag, 然后会为cell创建一个新的disposeBag对象,这样可以保证cell被重用的时候不会被多次订阅,造成错误。

视图控制器部分

import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {

let titles = ["自己选择的路,跪着也要把它走完。", "平凡的脚步也可以走完伟大的行程,世上没有绝望的处境,只有对处境绝望的人", "世上没有绝望的处境,只有对处境绝望的人", "第一个青春是上帝给的;第二个青春是靠自己努力的。", "每个人都会累,没人能为你承担所有悲伤,人总有一段时间要学会自己长大。", "每天醒来,敲醒自己的不是钟声,而是梦想。", "这个世界到处充满着不公平,我们能做的不仅仅是接受,还要试着做一些反抗。"]

lazy var tableView: UITableView = {
let tv = UITableView(frame: CGRect.zero, style: .plain)
tv.dataSource = self
tv.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell")
tv.estimatedRowHeight = 100
tv.rowHeight = UITableViewAutomaticDimension
return tv
}()
lazy var headView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.red
return view
}()

override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
}

func setupTableView() {
view.addSubview(tableView)
tableView.snp.makeConstraints { (make) in
make.left.right.top.bottom.equalToSuperview()
}
headView.frame = CGRect(x: 0, y: 0, width: view.bounds.size.width, height: 300)
tableView.tableHeaderView = headView
}
}

extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
cell.info.text = "\(titles[indexPath.row]): \(indexPath.row)"
cell.button.rx.tap.asObservable().subscribe(onNext: {
print("\(indexPath.row)")
}).disposed(by: cell.disposeBag)
return cell
}
}
很简单就是添加一个tableView设置相应的属性,并订阅点击事件。这样就可以正确处理按钮事件了。然后我们可以简化一下代码:class ViewController: UIViewController {

let disposeBag = DisposeBag()

let titles = ["自己选择的路,跪着也要把它走完。", "平凡的脚步也可以走完伟大的行程,世上没有绝望的处境,只有对处境绝望的人", "世上没有绝望的处境,只有对处境绝望的人", "第一个青春是上帝给的;第二个青春是靠自己努力的。", "每个人都会累,没人能为你承担所有悲伤,人总有一段时间要学会自己长大。", "每天醒来,敲醒自己的不是钟声,而是梦想。", "这个世界到处充满着不公平,我们能做的不仅仅是接受,还要试着做一些反抗。"]

lazy var tableView: UITableView = {
let tv = UITableView(frame: CGRect.zero, style: .plain)
tv.estimatedRowHeight = 100
tv.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell")
tv.rowHeight = UITableViewAutomaticDimension
return tv
}()
lazy var headView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.red
return view
}()

override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
bindTableView()
}

func setupTableView() {
view.addSubview(tableView)
tableView.snp.makeConstraints { (make) in
make.left.right.top.bottom.equalToSuperview()
}
headView.frame = CGRect(x: 0, y: 0, width: view.bounds.size.width, height: 300)
tableView.tableHeaderView = headView
}

func bindTableView() {
Observable.of(titles)
.bind(to: tableView.rx.items(cellIdentifier: "cell", cellType: CustomTableViewCell.self)) { (indexPath, element, cell) in
cell.info.text = element
cell.button.rx.tap.asObservable().subscribe(onNext: {
print(element)
}).disposed(by: cell.disposeBag)
}.disposed(by: disposeBag)
}
}

参考

在实践中应用RxSwift3处理cell
Invoked multiple times in UITableView
Avoid duplicate Subscription
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: