UICollectionView嵌套UIView无交互:didSelect不触发、无法滚动求助
解决UICollectionView无交互(点击/滚动失效)问题
我在UIView中嵌入UICollectionView后,控件完全失去交互能力——didSelect方法不触发,滚动也无法正常工作。相关实现代码如下:
import UIKit class AddressSelectionView: UIView { let mapImageView = UIImageView(image: UIImage(named: "sel_location_map_icon")) let lblTitle = AppLabel(font: .regularFont(ofSize: 18), text: "Select Location", color: .Hex_003032) let lblSubTitle = AppLabel(font: .regularFont(ofSize: 10), text: "Select the address where you are ordering", color: .okColor) lazy var addressCollectionView: UICollectionView = { let collectionView = UICollectionView(frame: bounds, collectionViewLayout: createLayout()) collectionView.delegate = self collectionView.dataSource = self collectionView.registerCell(SelectLocationHorizontalCell.self) collectionView.backgroundColor = .clear return collectionView }() private var selectedIndex: Int? init(name: String) { super.init(frame: .zero) setupUI() } override func layoutSubviews() { super.layoutSubviews() addressCollectionView.reloadData() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupUI() { isUserInteractionEnabled = true self.backgroundColor = .C2E6E0 self.setCornerRadius(10) let stack1 = UIStackView(arrangedSubviews: [lblTitle, lblSubTitle]) stack1.axis = .vertical stack1.alignment = .leading let view1 = UIView() view1.addSubview(stack1) stack1.snp.makeConstraints { make in make.center.leading.trailing.equalToSuperview() } let stack2 = UIStackView(arrangedSubviews: [view1, addressCollectionView]) stack2.axis = .vertical stack2.distribution = .fillEqually if let image = mapImageView.image { let ratio = image.size.height / image.size.width mapImageView.snp.makeConstraints { make in make.height.equalTo(mapImageView.snp.width).multipliedBy(ratio) } } let stackView = UIStackView(arrangedSubviews: [mapImageView, stack2]) stackView.axis = .horizontal stackView.alignment = .fill stackView.spacing = 8 self.addSubview(stackView) stackView.snp.makeConstraints { make in make.edges.equalTo(self)//.inset(UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12)) } } private func createLayout() -> UICollectionViewLayout { let item = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .estimated(100), heightDimension: .fractionalHeight(1))) let size = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)) let group = NSCollectionLayoutGroup.vertical(layoutSize: size, subitems: [item]) let layoutSection = NSCollectionLayoutSection(group: group) return UICollectionViewCompositionalLayout(section: layoutSection) } } extension AddressSelectionView: UICollectionViewDelegate, UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 10 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(SelectLocationHorizontalCell.self, for: indexPath) cell.nameLabel.text = "Hello Ravi" cell.isSelectGredientCell(selectedIndex == indexPath.row) return cell } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { selectedIndex = indexPath.row collectionView.reloadData() } }
Cell代码:
class SelectLocationHorizontalCell: UICollectionViewCell, NibLoadableView, ReusableView { @IBOutlet weak var nameLabel : UILabel! @IBOutlet weak var gredientView : GradientView! override func awakeFromNib() { super.awakeFromNib() self.nameLabel.font = UIFont.regularFont(ofSize: 10) gredientView.setCornerRadius(10 * Screen.Scale) setCornerRadius(10 * Screen.Scale) self.applyShadow(5 * Screen.Scale, CGSize.init(width: 0, height:5 * Screen.Scale), UIColor.init(red: 0, green: 0.19, blue: 0.2, alpha: 0.2), 1) } func isSelectGredientCell(_ isSelectCell : Bool) { if isSelectCell { self.gredientView.setGredientColors(colors: [UIColor.colorFromHex("EFEDD6").cgColor, UIColor.colorFromHex("FFCC46").cgColor]) } else { self.gredientView.setGredientColors(colors: [UIColor.colorFromHex("C2E6E0").cgColor, UIColor.colorFromHex("BAD09D").cgColor]) } } func configureCell(_ model: AddressModel?, isSelected: Bool) { nameLabel.text = model?.addressName self.isSelectGredientCell(isSelected) } func configureCell(_ model: AddressModel?, selectedAddressModel : AddressModel?) { nameLabel.text = model?.addressName self.isSelectGredientCell(model == selectedAddressModel) } func configureFamilyMemberData(_ model: DependentPersonModel?, selectedFamilyMembers : DependentPersonModel?) { nameLabel.text = model?.dependentName self.isSelectGredientCell(model?.familyDependentsID == selectedFamilyMembers?.familyDependentsID) } } class GradientView: UIView { override open class var layerClass: AnyClass { return CAGradientLayer.classForCoder() } func setGredientColors(colors : [CGColor]) { let gradientLayer = layer as! CAGradientLayer gradientLayer.colors = colors } }
解决要点
- 修复CollectionView初始化frame
懒加载创建addressCollectionView时,初始用bounds会因为父视图还没布局导致frame错误,直接用.zero让AutoLayout接管:
lazy var addressCollectionView: UICollectionView = { let collectionView = UICollectionView(frame: .zero, collectionViewLayout: createLayout()) // 其他配置不变 }()
调整布局配置,让CollectionView支持滚动
当前布局的item和group高度都是fractionalHeight(1),所有cell会挤在一起没有滚动空间。根据需求修改:- 垂直滚动:给cell设置固定高度
private func createLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(44)) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(44)) let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.interGroupSpacing = 8 return UICollectionViewCompositionalLayout(section: section) }- 横向滚动:开启正交滚动行为
private func createLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(100), heightDimension: .fractionalHeight(1)) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .estimated(100), heightDimension: .fractionalHeight(1)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.orthogonalScrollingBehavior = .continuous section.interGroupSpacing = 8 return UICollectionViewCompositionalLayout(section: section) }移除layoutSubviews中的reloadData
每次布局都刷新会干扰交互,直接删除:
override func layoutSubviews() { super.layoutSubviews() // addressCollectionView.reloadData() // 删除此行 }
- 调整StackView布局分配
stack2用.fillEqually可能导致CollectionView空间不足,改为.fill让它占据剩余空间:
let stack2 = UIStackView(arrangedSubviews: [view1, addressCollectionView]) stack2.axis = .vertical stack2.distribution = .fill stack2.setCustomSpacing(12, after: view1)
- 确认Cell交互状态
确保Cell及其子视图的isUserInteractionEnabled为true(默认是true,若被修改过需恢复):
// 在SelectLocationHorizontalCell的awakeFromNib中添加 self.isUserInteractionEnabled = true gredientView.isUserInteractionEnabled = true
内容的提问来源于stack exchange,提问作者rv7284
相关产品推荐
相关产品推荐

