RxSwift - UITableViewCell上按钮事件处理
2018-01-29 11:11
3047 查看
RxSwift与UITableView的使用,之前文章简单的实现了一下。今天主要是实现如何处理UITableViewCell上的按钮事件。以前我们通常会选择使用代理、闭包、通知这些方法中的一个方法,我个人喜欢闭包。但是现在已经开始使用RxSwift,所以一起来看看RxSwift中我们如何处理按钮事件。
UITableViewCell的内部事件
一般对于cell的点击,会触发其代理方法: func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// 处理cell的点击事件
}在Rx中,我们处理如下:
由上可知对于cell的处理还是很简单的。
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被重用的时候不会被多次订阅,造成错误。
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)
}
}
Invoked multiple times in UITableView
Avoid duplicate Subscription
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 UIKitimport 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处理cellInvoked multiple times in UITableView
Avoid duplicate Subscription
相关文章推荐
- IOS UITableViewCell详解及按钮点击事件处理实例
- IOS--UITableViewCell上的按钮点击事件处理
- UITableViewCell上的按钮点击事件处理
- Swift UITableViewCell中的按钮点击事件
- UITableViewCell有关处理touch事件的问题
- iOS-UITableView-处理cell上按钮事件(弹出警示框,页面跳转等)
- UITableView 中实现 滑动一个cell 显示一个按钮,并且做相关业务处理
- 使用IDA对MFC寻找按钮处理事件
- android开发步步为营之22:处理Activity中的back按钮事件
- 转: (论坛答疑点滴)winform下怎么得到按钮的click事件的处理方法
- [JS][技巧]利用事件冒泡特性处理多个按钮的单击事件
- ios8 UITableVIewCell 侧滑显示多个按钮
- 自定义listview,带按钮,多选框,处理item事件
- <html:cancel cancel 取消按钮事件处理
- 4.2设计具有背景图的按钮—ImageButton的焦点及事件处理
- iOS 自定义Cell按钮的点击代理事件
- 《android按钮点击事件的频繁点击问题处理》
- iOS UITableViewCell添加按钮 点击按钮改变按钮状态之坑
- Jquery中的事件处理(自动触发事件,禁用按钮,悬停,失焦,滑动效果)
- 【Android 开发入门】为按钮添加Click单击事件处理程序,显示/隐藏另一个按钮