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

Swift中基于UICollectionView/UIScrollView实现带平移缩放的自由画板

Swift自由画板:UICollectionView vs UIScrollView选型建议

选型分析

UIScrollView 更适配自由画板场景

  • 原生支持平移(滚动)和缩放功能,无需额外实现复杂手势逻辑
  • 布局灵活性拉满:可直接将便签作为子视图添加,自由控制每个便签的位置、大小,完美匹配"随机添加"的需求
  • 实现成本低:只需设置minimumZoomScale/maximumZoomScale,并实现UIScrollViewDelegate的viewForZooming(in:)方法即可完成缩放基础功能

UICollectionView 仅适合特定场景

  • 仅当便签需要固定布局规则(如网格、列表、环状),且数量极大需要复用机制时,才考虑使用
  • 自定义Layout成本高:你当前实现的六边形布局和自由放置需求不匹配,且缩放需要额外处理元素transform与布局失效逻辑

UICollectionView 缩放实现优化示例

针对你当前的自定义Layout,以下是修正后的缩放方案,解决手势冲突与缩放逻辑生硬的问题:

final public class CustomCollectionViewLayout: UICollectionViewLayout, UIGestureRecognizerDelegate {

    private let maxScale: CGFloat = 2.0
    private let minScale: CGFloat = 0.5

    public override func prepare() {
        super.prepare()
        // 复用UICollectionView(继承自UIScrollView)的原生缩放能力
        collectionView?.minimumZoomScale = minScale
        collectionView?.maximumZoomScale = maxScale
    }

    public override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let originalAttributes = super.layoutAttributesForElements(in: rect),
              let collectionView = collectionView else {
            return nil
        }
        
        return originalAttributes.map { attr in
            let copiedAttr = attr.copy() as! UICollectionViewLayoutAttributes
            // 基于scrollView的实时缩放比例调整元素
            let scale = collectionView.zoomScale
            copiedAttr.transform = CGAffineTransform(scaleX: scale, y: scale)
            return copiedAttr
        }
    }

    public override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        // 边界变化时重新计算布局
        return true
    }

    // 允许手势同时识别,避免与scrollView原生手势冲突
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return otherGestureRecognizer is UIPanGestureRecognizer || otherGestureRecognizer is UIPinchGestureRecognizer
    }
}

配套使用说明

  1. 你的ViewController需实现UIScrollViewDelegate:
class BoardViewController: UIViewController, UIScrollViewDelegate {
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        // 返回用于缩放的容器视图,可复用collectionView本身或其背景视图
        return collectionView
    }
}
  1. 移除自定义的zoomIn/zoomOut方法,依赖UIScrollView原生缩放逻辑,交互更流畅且符合系统规范

你当前代码的核心问题

  • 自定义捏合手势与UICollectionView原生滚动手势冲突,导致交互卡顿
  • 缩放逻辑采用固定步长修改currentScale,而非基于手势实际缩放比例,体验生硬
  • 布局计算的元素位置固定,缩放后未适配内容偏移

内容的提问来源于stack exchange,提问作者ajinkya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 13:59:54