You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 06:18:22