能否使用XIB在UICollectionViewListCell中创建自定义视图?
用XIB实现UICollectionViewListCell自定义视图+编辑功能
完全可以用XIB实现这个需求,不用依赖SwiftUI。下面是具体的实现步骤和代码示例:
1. 创建自定义内容视图的XIB
- 新建一个
UIView子类(命名为CustomContentView),同时创建对应的XIB文件 - 在XIB中添加你需要的控件(比如
UIButton、UITextView),设置好约束确保控件布局正确 - 在
CustomContentView类中关联XIB里的控件,提供配置方法方便后续更新内容:
import UIKit class CustomContentView: UIView { @IBOutlet weak var titleButton: UIButton! @IBOutlet weak var contentTextView: UITextView! func configure(with title: String, content: String) { titleButton.setTitle(title, for: .normal) contentTextView.text = content } // 从XIB加载的类方法 static func loadFromNib() -> CustomContentView { let nib = UINib(nibName: "CustomContentView", bundle: nil) return nib.instantiate(withOwner: nil, options: nil).first as! CustomContentView } }
2. 自定义UICollectionViewListCell子类
创建UICollectionViewListCell的子类(命名为CustomListCell),在其中加载并添加自定义内容视图:
import UIKit class CustomListCell: UICollectionViewListCell { private var customContentView: CustomContentView! override init(frame: CGRect) { super.init(frame: frame) setupContentView() } required init?(coder: NSCoder) { super.init(coder: coder) setupContentView() } private func setupContentView() { customContentView = CustomContentView.loadFromNib() customContentView.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(customContentView) // 设置约束让自定义视图铺满contentView NSLayoutConstraint.activate([ customContentView.topAnchor.constraint(equalTo: contentView.topAnchor), customContentView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), customContentView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), customContentView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) ]) // 配置cell的更新逻辑 configurationUpdateHandler = { [weak self] cell, state in guard let self = self else { return } // 根据状态更新accessories var accessories: [UICellAccessory] = [] if state.isEditing { accessories.append(.reorder()) accessories.append(.delete()) } cell.accessories = accessories // 从configuration中获取数据更新自定义视图 if let config = cell.configuration as? CustomCellConfiguration { self.customContentView.configure(with: config.title, content: config.content) } } } } // 自定义Configuration,用于传递cell数据 struct CustomCellConfiguration: UIContentConfiguration, Hashable { var title: String var content: String func makeContentView() -> UIView & UIContentView { fatalError("不需要实现,因为我们用自定义视图") } func updated(for state: UIConfigurationState) -> CustomCellConfiguration { return self } }
3. 配置UICollectionView
在ViewController中设置collectionView的布局、注册cell,并实现编辑和滑动删除逻辑:
import UIKit class ViewController: UIViewController { private var collectionView: UICollectionView! private var data = ["Item 1", "Item 2", "Item 3"].map { (title: $0, content: "Content for \($0)") } override func viewDidLoad() { super.viewDidLoad() setupCollectionView() // 添加编辑按钮 navigationItem.rightBarButtonItem = editButtonItem } private func setupCollectionView() { // 使用列表布局 let layout = UICollectionViewCompositionalLayout.list(using: UICollectionLayoutListConfiguration(appearance: .insetGrouped)) collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout) collectionView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(collectionView) NSLayoutConstraint.activate([ collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) // 注册自定义cell collectionView.register(CustomListCell.self, forCellWithReuseIdentifier: "CustomListCell") collectionView.dataSource = self collectionView.delegate = self // 允许编辑时的操作 collectionView.allowsSelectionDuringEditing = true collectionView.allowsMultipleSelectionDuringEditing = true } override func setEditing(_ editing: Bool, animated: Bool) { super.setEditing(editing, animated: animated) collectionView.setEditing(editing, animated: animated) } } // MARK: - UICollectionViewDataSource extension ViewController: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return data.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomListCell", for: indexPath) as! CustomListCell let item = data[indexPath.item] cell.configuration = CustomCellConfiguration(title: item.title, content: item.content) return cell } // 处理删除 func collectionView(_ collectionView: UICollectionView, commit editingStyle: UICollectionViewCell.EditingStyle, forItemAt indexPath: IndexPath) { if editingStyle == .delete { data.remove(at: indexPath.item) collectionView.deleteItems(at: [indexPath]) } } // 允许重排 func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool { return true } // 处理重排 func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { let movedItem = data.remove(at: sourceIndexPath.item) data.insert(movedItem, at: destinationIndexPath.item) } } // MARK: - UICollectionViewDelegate extension ViewController: UICollectionViewDelegate { // 实现滑动删除 func collectionView(_ collectionView: UICollectionView, trailingSwipeActionsConfigurationForItemAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let deleteAction = UIContextualAction(style: .destructive, title: "删除") { [weak self] _, _, completion in guard let self = self else { return } self.data.remove(at: indexPath.item) collectionView.deleteItems(at: [indexPath]) completion(true) } return UISwipeActionsConfiguration(actions: [deleteAction]) } }
关键说明
- 自定义内容视图通过XIB创建,完全复用你之前的XIB开发习惯
UICollectionViewListCell的accessories属性在编辑模式下自动添加重排和删除控件,无需额外自定义- 通过自定义
UIContentConfiguration传递数据,配合configurationUpdateHandler统一更新cell状态和内容 - 用标准的UICollectionView代理方法实现删除、重排和滑动删除逻辑,和传统UICollectionCell的编辑逻辑完全兼容
内容的提问来源于stack exchange,提问作者Cheok Yan Cheng
相关产品推荐
相关产品推荐

