Swift:如何根据UserDefaults数据切换CollectionViewCell中的按钮?
解决从UserDefaults取数据控制CollectionViewCell按钮显示的问题
核心思路
不要在cell初始化阶段做按钮显示判断——此时cell的业务数据还未绑定,UserDefaults的判断会基于空数据导致逻辑失效。正确做法是:在cell的专属配置方法中,先读取UserDefaults数据,再结合当前业务数据决定按钮的显示状态、样式等。
具体实现步骤
1. 给CollectionViewCell添加配置方法
修改ItemsCollectionViewCell,新增统一配置方法,把数据赋值、按钮逻辑判断都整合到这里:
class ItemsCollectionViewCell: UICollectionViewCell { static let reuseId = "ItemsCollectionViewCell" var textItem: String = "" var categoryItem: String = "" var costItem: Int = 0 var imageItem: String = "" let addCartButton: UIButton = { let button = UIButton(type: .system) button.backgroundColor = .gray button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 12) button.setTitle("В корзину", for: .normal) button.setTitleColor(.white, for: .normal) button.translatesAutoresizingMaskIntoConstraints = false button.layer.cornerRadius = 12 button.addTarget(self, action: #selector(tappedAddCart), for: .touchUpInside) return button }() override init(frame: CGRect) { super.init(frame: frame) setupViews() // 初始化时默认隐藏按钮,等配置时再决定显示状态 addCartButton.isHidden = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupViews() { // 添加按钮到视图并设置约束 contentView.addSubview(addCartButton) NSLayoutConstraint.activate([ addCartButton.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8), addCartButton.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8), addCartButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8), addCartButton.heightAnchor.constraint(equalToConstant: 32) ]) // 其他视图的布局代码... } // 核心配置方法:接收商品数据,同步UI和UserDefaults逻辑 func configure(with item: YourItemModel) { // 绑定业务数据 textItem = item.title costItem = item.price imageItem = item.imageUrl categoryItem = "test" // 读取UserDefaults中已加入购物车的商品ID列表 let defaults = UserDefaults.standard let cartItemIds = defaults.array(forKey: "cartItemIds") as? [String] ?? [] // 根据UserDefaults数据判断按钮状态 let isInCart = cartItemIds.contains(item.id) // 假设商品模型有唯一id属性 addCartButton.isHidden = isInCart if !isInCart { addCartButton.setTitle("В корзину", for: .normal) addCartButton.backgroundColor = .gray addCartButton.isUserInteractionEnabled = true } else { // 已加入购物车时的按钮样式 addCartButton.setTitle("已加入", for: .normal) addCartButton.backgroundColor = .green addCartButton.isUserInteractionEnabled = false } // 处理图片和标签赋值 if let imageUrl = URL(string: item.imageUrl), let imageData = try? Data(contentsOf: imageUrl) { mainImageView.image = UIImage(data: imageData) } else { mainImageView.image = UIImage(systemName: "photo") // 占位图 } nameLabel.text = item.title costLabel.text = "\(item.price) руб." nameLabel.textAlignment = .center costLabel.textAlignment = .center } @objc private func tappedAddCart() { // 点击按钮后,将商品ID存入UserDefaults let defaults = UserDefaults.standard var cartItemIds = defaults.array(forKey: "cartItemIds") as? [String] ?? [] cartItemIds.append(textItem) // 建议替换为商品唯一ID defaults.set(cartItemIds, forKey: "cartItemIds") // 同步更新按钮状态 addCartButton.isHidden = true } }
2. 简化CollectionView的cell配置逻辑
在ItemsCollectionView的cellForItemAt方法中,直接调用cell的配置方法,无需零散赋值:
class ItemsCollectionView: UICollectionView, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { // 假设你的商品数据模型为YourItemModel var cells: [YourItemModel] = [] func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = dequeueReusableCell(withReuseIdentifier: ItemsCollectionViewCell.reuseId, for: indexPath) as! ItemsCollectionViewCell // 直接传入当前商品数据完成配置 cell.configure(with: cells[indexPath.row]) return cell } // 其他代理方法... }
关键注意事项
- 避免初始化阶段处理业务逻辑:cell初始化时无绑定数据,此时读取UserDefaults做判断会得到错误结果。
- 统一配置方法管理状态:所有UI状态、数据绑定都放到
configure方法中,保证cell状态与数据同步,避免复用旧cell的错误状态。 - UserDefaults读写规范:如果涉及多线程操作,可手动调用
defaults.synchronize()(iOS 10+后系统自动同步,特殊场景需手动处理)。
内容的提问来源于stack exchange,提问作者user20766085
相关产品推荐
相关产品推荐

