Нажатие кнопки в UICollectionViewCell также переключает состояние в другой ячейке - PullRequest
0 голосов
/ 22 октября 2019

У меня есть UICollectionViewCell, который содержит UIButton.

При нажатии кнопки в ячейке я хочу переключить состояние 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 и просто позволю кнопкам переключаться, ошибка не существует. Интересно, если ответ перезагружает представление коллекции и из-за повторного использования обновляется неправильное состояние кнопки.

РЕДАКТИРОВАТЬ 2

Если я инициирую вызов API с помощьюпри выборе ячейки вместо кнопки все работает, однако я бы хотел, чтобы это происходило при нажатии кнопки.

Я подозреваю, что это все же связано с состоянием кнопки.

enter image description here

1 Ответ

0 голосов
/ 22 октября 2019

Как предполагает Субраманиан Мариапан, это может быть из-за повторного использования клеток. В своем методе render вы подписываетесь на нажатие кнопки и фактически никогда не прекращаете наблюдать. Замените:

private let disposeBag = DisposeBag()

на:

private var disposeBag = DisposeBag()

и в func prepareForReuse() добавьте создание нового disposeBag (который, кстати, освободит старый).

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

        disposeBag = DisposeBag()
    }
...