UICollectionViewCell中的按钮点击也可以切换另一个单元格中的状态

问题描述 投票:0回答:1

我有一个包含UICollectionViewCellUIButton

[在单元格中点击按钮时,我想切换selected状态。

这在一定程度上有效,我看到的错误是,单击1个单元格也会切换另一个单元格的状态。


import UIKit
import RxSwift

class PersonaliseYourAppsListCell: BaseCollectionViewCell<Launcher> {

    let toggleSelectedTrigger = PublishSubject<String>()

    private let disposeBag = DisposeBag()

    override init(frame: CGRect) {
        super.init(frame: frame)

        configureSubviews()
    }

    required init?(coder: NSCoder) {
        return nil
    }

    override func render(with model: Launcher?) {
        guard let model = model else { return }

        title.text = model.name
        icon.image = model.icon

        toggleButton.rx.tap.bind { [weak self] in
            self?.toggleButton.isSelected.toggle()
            self?.toggleSelectedTrigger.onNext(model.id)
        }.disposed(by: disposeBag)

        if let status = model.status {
            toggleButton.isSelected = model.selected ?? false
            toggleButton.isUserInteractionEnabled = status != .forced

            [title, icon, toggleButton].forEach {
                $0.alpha = status == .forced ? 0.6 : 1
            }

            if status == .forced {
                addSubviews(enforcedLabel)
                enforcedLabel.position(top: title.bottomAnchor, leading: title.leadingAnchor, withPadding: .zero)
            }
        }
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        enforcedLabel.removeFromSuperview()
    }

    // MARK:- UI Elements

    private func configureSubviews() {
        addSubviews(icon, title, toggleButton, separatorView)

        icon
            .isCenteredY()
            .position(
                leading: leadingAnchor,
                withPadding: .init(top: 0, left: 16, bottom: 0, right: 4)
        )

        title
            .isCenteredY()
            .position(
                leading: icon.trailingAnchor, trailing: toggleButton.leadingAnchor,
                withPadding: .init(top: 0, left: 8, bottom: 0, right: 8)
        )

        toggleButton
            .isCenteredY()
            .withSize(.init(width: 44, height: 44))
            .position(trailing: trailingAnchor, withPadding: .init(top: 0, left: 0, bottom: 0, right: 16))

        separatorView
            .isCenteredX()
            .withSize(.init(width: frame.width - 48, height: 1))
            .position(bottom: bottomAnchor)
    }

    private lazy var icon: UIImageView = {
        let iv = UIImageView(frame: .zero)
        iv.contentMode = .scaleAspectFit
        [iv.widthAnchor, iv.heightAnchor].forEach { $0.constraint(equalToConstant: 64).isActive = true }
        return iv
    }()

    private lazy var title: UILabel = {
        let label = UILabel(frame: .zero)
        label.font = .systemFont(ofSize: 20)
        label.textAlignment = .left
        label.numberOfLines = 2
        label.textColor = .usingHex("444444")
        return label
    }()

    private lazy var toggleButton: CheckBoxButton = {
        let button = CheckBoxButton(type: .custom)
        return button
    }()

    private lazy var enforcedLabel: UILabel = {
        let label = UILabel(frame: .zero)
        label.text = "This app cannot be removed"
        label.font = .systemFont(ofSize: 12)
        label.textColor = .lightGray
        return label
    }()

    private lazy var separatorView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor(white: 0.3, alpha: 0.1)
        return view
    }()
}

我的CollectionView的设置如下:

    override func viewDidLoad() {
        super.viewDidLoad()

        presenter?.viewIsReady.onNext(())

        presenter?.data.bind(to: customView.collectionView.rx.items) { [weak self] (cv, row, item) -> UICollectionViewCell in

            let cell = cv.dequeueReusableCell(withClass: PersonaliseYourAppsListCell.self, for: .init(row: row, section: 0))
            cell.render(with: item)

            if let self = self, let presenter = self.presenter {
                cell.toggleSelectedTrigger.bind(to: presenter.updateUserAppsTrigger).disposed(by: self.disposeBag)
            }

            return cell

        }.disposed(by: disposeBag)

        customView.configureLayout()
    }

编辑

我注意到,如果我不进行api调用,而只是让按钮状态切换,则该bug不存在。我想知道响应是否正在重新加载集合视图,并且由于重新使用而导致错误的按钮状态正在更新。

编辑2

如果我通过选择单元格而不是按钮来触发API调用,那么一切正常,但是我希望在单击按钮时发生这种情况。

我仍然怀疑这与按钮状态有关。

enter image description here

ios swift uicollectionview uicollectionviewcell rx-swift
1个回答
0
投票

正如Subramanian Mariappan所建议的,可能是因为细胞被重用。在render方法中,您订阅了按钮点击操作,而您实际上从未停止观察。替换:

private let disposeBag = DisposeBag()

with:

private var disposeBag = DisposeBag()

并且在func prepareForReuse()中添加新的disposeBag的创建(顺便释放旧的DisposeBag)。

    override func prepareForReuse() {
        super.prepareForReuse()
        enforcedLabel.removeFromSuperview()

        disposeBag = DisposeBag()
    }

0
投票

正如Subramanian Mariappan所建议的,可能是因为细胞被重用。在render方法中,您订阅了按钮点击操作,而您实际上从未停止观察。替换:

private let disposeBag = DisposeBag()

with:

private var disposeBag = DisposeBag()

并在func prepareForReuse()中添加新的disposeBag的创建(顺便释放旧的DisposeBag)。

    override func prepareForReuse() {
        super.prepareForReuse()
        enforcedLabel.removeFromSuperview()

        disposeBag = DisposeBag()
    }
© www.soinside.com 2019 - 2024. All rights reserved.