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

使用Storyboards与Swift实现可展开Collection view cell弹窗方案咨询

问题1:是否可以在Storyboards中直接配置同一个cell的折叠、展开两种视图?

可以实现,操作方式如下:

  • 打开Storyboard中对应CollectionView的自定义cell原型,同时添加折叠态、展开态所需的所有UI组件
  • 给两种状态的布局约束设置不同的优先级:默认折叠状态下,折叠相关的宽高、内部组件约束优先级设为999,展开相关约束优先级设为250;也可以将两类约束分别关联为自定义cell的IBOutlet属性,切换状态时主动激活/停用对应约束,避免冲突
  • 展开态默认不需要显示的组件,直接在Storyboard属性面板勾选Hidden,状态切换时修改isHidden属性即可
  • 如果展开弹窗会超出原cell的显示范围,直接将弹窗层作为cell的子视图默认隐藏即可,不需要额外新建cell原型
问题2:代码层面实现方案

你可以参考以下步骤实现完整逻辑:

1. 预定义属性

首先在ViewController中添加两个全局属性做状态管理:

// 记录当前展开的cell下标,默认无展开
var currentExpandedIndexPath: IndexPath?
// 存储模糊背景视图
weak var blurBackgroundView: UIVisualEffectView?

同时在自定义cell中实现两个状态切换的方法:

// 切换到展开态
func switchToExpandedState() {
    // 停用折叠约束,激活展开约束
    foldedConstraints.forEach { $0.isActive = false }
    expandedConstraints.forEach { $0.isActive = true }
    // 切换UI显隐
    foldedViews.forEach { $0.isHidden = true }
    expandedViews.forEach { $0.isHidden = false }
    layoutIfNeeded()
}

// 切换到折叠态
func switchToFoldedState() {
    expandedConstraints.forEach { $0.isActive = false }
    foldedConstraints.forEach { $0.isActive = true }
    expandedViews.forEach { $0.isHidden = true }
    foldedViews.forEach { $0.isHidden = false }
    layoutIfNeeded()
}

2. 点击cell触发状态切换

实现CollectionView的点击代理:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    // 已经有展开的cell,且不是当前点击的,先收起已展开的
    if let expandedIndex = currentExpandedIndexPath, expandedIndex != indexPath {
        collapseExpandedCell()
    }
    // 切换当前cell状态
    if currentExpandedIndexPath == indexPath {
        collapseExpandedCell()
    } else {
        expandCell(at: indexPath)
    }
}

3. 展开逻辑实现

private func expandCell(at indexPath: IndexPath) {
    // 禁用CollectionView滚动
    collectionView.isScrollEnabled = false
    // 添加模糊背景
    let blurEffect = UIBlurEffect(style: .systemUltraThinMaterialDark)
    let blurView = UIVisualEffectView(effect: blurEffect)
    blurView.frame = view.bounds
    blurView.alpha = 0
    // 点击模糊背景收回
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(collapseExpandedCell))
    blurView.addGestureRecognizer(tapGesture)
    view.addSubview(blurView)
    self.blurBackgroundView = blurView
    
    // 拿到点击的cell,转换坐标到VC根视图
    guard let cell = collectionView.cellForItem(at: indexPath) as? YourCustomCell else { return }
    let originalCellFrame = cell.convert(cell.bounds, to: view)
    // 将cell从CollectionView移到VC根视图层级,放在模糊层上方
    view.addSubview(cell)
    cell.frame = originalCellFrame
    currentExpandedIndexPath = indexPath
    
    // 动画展开到全屏3/5大小
    let expandedHeight = view.bounds.height * 3 / 5
    let targetFrame = CGRect(
        x: 0,
        y: (view.bounds.height - expandedHeight) / 2,
        width: view.bounds.width,
        height: expandedHeight
    )
    UIView.animate(withDuration: 0.3) {
        blurView.alpha = 1
        cell.frame = targetFrame
        cell.switchToExpandedState()
    }
}

4. 收回逻辑实现

@objc private func collapseExpandedCell() {
    guard let expandedIndex = currentExpandedIndexPath,
          let cell = view.subviews.first(where: { $0 is YourCustomCell }) as? YourCustomCell,
          let originalLayout = collectionView.layoutAttributesForItem(at: expandedIndex) else { return }
    // 转换原cell在CollectionView中的坐标到根视图
    let originalFrameInVC = collectionView.convert(originalLayout.frame, to: view)
    
    UIView.animate(withDuration: 0.3, animations: {
        self.blurBackgroundView?.alpha = 0
        cell.frame = originalFrameInVC
        cell.switchToFoldedState()
    }) { [weak self] _ in
        guard let self = self else { return }
        // 把cell移回CollectionView
        self.collectionView.addSubview(cell)
        cell.frame = originalLayout.frame
        // 清理资源
        self.blurBackgroundView?.removeFromSuperview()
        self.blurBackgroundView = nil
        // 恢复滚动
        self.collectionView.isScrollEnabled = true
        self.currentExpandedIndexPath = nil
    }
}

内容的提问来源于stack exchange,提问作者Peter Hlavatík

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 15:15:04