如何使用 RxDataSources 避免重复点击 Tableview 上的按钮

Posted

技术标签:

【中文标题】如何使用 RxDataSources 避免重复点击 Tableview 上的按钮【英文标题】:How to avoid duplicate tap on button on Tableview with RxDataSources 【发布时间】:2019-01-02 13:21:43 【问题描述】:

我有一个带有 RxDataSources 的表格视图,其中单元格项目有一个删除图标。当单元格出列并单击该删除图标时,将触发所有先前的单击事件,从而重复点击。 项目单元格:

 removeImageView.rx.tap().map  _ in indexPath  
            .bind(to: viewModel.onRemoveItem).disposed(by: cellDisposeBag)

单元格视图模型:

let onRemoveItem = PublishSubject<IndexPath>()

单元格和 ViewModel 绑定的视图控制器视图模型:

 let vm = ItemViewModel(with: item)
            vm.onRemoveItem.bind(to: self.onRemoveItem).disposed(by: self.rx.disposeBag)

            return SectionItem.item(viewModel: vm)

视图控制器:

let dataSource = RxTableViewSectionedReloadDataSource<SectionItem>(configureCell:  dataSource, tableView, indexPath, item in
    switch item 
    case .item(let viewModel):
        let cell = (tableView.dequeueReusableCell(withIdentifier: itemtIdentifier, for: indexPath) as? ItemCell)!
        cell.bind(to: viewModel, at: indexPath)
        return cell
    
, titleForHeaderInSection:  dataSource, index in
    let section = dataSource[index]
    return section.title
  )

output?.items
    .bind(to: tableView.rx.items(dataSource: dataSource))
    .disposed(by: rx.disposeBag)

output?.onRemoveCartIemTapped.distinctUntilChanged() 
    .skip(1)
    .distinctUntilChanged().drive(onNext:  [weak self] (indexPath) in
    print("onRemoveCartIemTapped" + String(indexPath.item))
).disposed(by: rx.disposeBag)

控制台调试:

onRemoveCartIemTapped0
onRemoveCartIemTapped3
onRemoveCartIemTapped1
onRemoveCartIemTapped4

【问题讨论】:

你有一个示例项目吗?我想帮你解决这个问题。这应该很容易,但我通常在 ViewModel 中使用 tableView 的委托和数据源方法的正常实现,而不使用 RxSwift 的扩展(但在整个项目中使用 RxSwift,而不仅仅是在 tableViews 中)。 您是否在单元格的prepareForReuse 方法中处理cellDisposeBag?如果在没有处理订阅的情况下重复使用单元格,则可能会导致这种行为。 不,我根本不使用 prepareForReuse。即使在点击按钮时我有单元格处理,我该怎么做 @Paul 我修好了,谢谢 :)。发表您的评论作为答案。 【参考方案1】:

这是由UITableView 重用单元格引起的。为避免有多个订阅,您可以覆盖单元格的 prepareForReuse() 方法并确保释放所有现有订阅。

我通常将DisposeBag 声明为一个var,然后在prepareForReuse() 中为其分配一个新的DisposeBag。当DisposeBag 被取消初始化时,它将释放它包含的所有订阅。比如:

override func prepareForReuse() 
    super.prepareForReuse()

    cellDisposeBag = DisposeBag()

【讨论】:

DisposeBag 被取消初始化时

以上是关于如何使用 RxDataSources 避免重复点击 Tableview 上的按钮的主要内容,如果未能解决你的问题,请参考以下文章

当我使用 RxDatasources 更新数据源时,不会触发 configureCell

RxDataSources`无法推断通用参数'Self'`

如何避免jQuery UI可拖动也触发点击事件[重复]

如何避免jQuery UI可拖动也触发点击事件[重复]

避免表单重复提交的几种方法

如何避免表单重复提交