У меня есть 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 с помощьюпри выборе ячейки вместо кнопки все работает, однако я бы хотел, чтобы это происходило при нажатии кнопки.
Я подозреваю, что это все же связано с состоянием кнопки.