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

如何在SwiftUI中实现PKCanvasView缩放与正常绘图兼容?

解决ScrollView与PKCanvasView的手势冲突问题

要实现单指绘图、双指缩放平移的Freeform式交互,核心是让ScrollView只响应双指手势,单指手势优先交给PKCanvasView处理。以下是具体实现方案:

1. 自定义ScrollView子类

创建继承自UIScrollView的子类,重写手势识别逻辑,限制ScrollView仅响应双指操作:

class CanvasScrollView: UIScrollView, UIGestureRecognizerDelegate {
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupConfig()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupConfig()
    }
    
    private func setupConfig() {
        delegate = self
        // 配置缩放范围
        minimumZoomScale = 0.5
        maximumZoomScale = 5.0
    }
    
    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        // 单指平移手势:交给PKCanvasView处理,禁止ScrollView响应
        if let panGesture = gestureRecognizer as? UIPanGestureRecognizer {
            return panGesture.numberOfTouches != 1
        }
        // 捏合缩放手势:正常响应
        if gestureRecognizer is UIPinchGestureRecognizer {
            return true
        }
        return super.gestureRecognizerShouldBegin(gestureRecognizer)
    }
}

2. 用SwiftUI包装自定义ScrollView

创建UIViewRepresentable结构体,将自定义ScrollView包装为SwiftUI视图,并嵌入你的CanvasView:

struct ZoomableCanvasContainer: UIViewRepresentable {
    @Binding var canvasView: PKCanvasView
    let onSaved: () -> Void
    
    func makeUIView(context: Context) -> CanvasScrollView {
        let scrollView = CanvasScrollView()
        // 生成CanvasView对应的UIView实例
        let canvasUIView = CanvasView(canvasView: $canvasView, onSaved: onSaved).makeUIView(context: context)
        canvasUIView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.addSubview(canvasUIView)
        
        // 设置约束,让CanvasView填充ScrollView
        NSLayoutConstraint.activate([
            canvasUIView.topAnchor.constraint(equalTo: scrollView.topAnchor),
            canvasUIView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
            canvasUIView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
            canvasUIView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
            canvasUIView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
            canvasUIView.heightAnchor.constraint(equalTo: scrollView.heightAnchor)
        ])
        
        // 设置缩放代理,指定PKCanvasView为缩放视图
        scrollView.delegate = context.coordinator
        context.coordinator.canvasView = canvasUIView
        
        return scrollView
    }
    
    func updateUIView(_ uiView: CanvasScrollView, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator: NSObject, UIScrollViewDelegate {
        weak var canvasView: PKCanvasView?
        
        func viewForZooming(in scrollView: UIScrollView) -> UIView? {
            canvasView
        }
    }
}

3. 在SwiftUI中使用包装容器

替换原有ScrollView,用ZoomableCanvasContainer承载绘图视图:

struct ContentView: View {
    @State private var canvasView = PKCanvasView()
    
    private func saveDrawing() {
        // 你的绘图保存逻辑
    }
    
    var body: some View {
        ZoomableCanvasContainer(canvasView: $canvasView, onSaved: saveDrawing)
            .edgesIgnoringSafeArea(.all)
    }
}

额外优化:修正PKCanvasView绘图策略

确保CanvasView中的绘图策略适配真机与模拟器:

func makeUIView(context: Context) -> PKCanvasView {
    canvasView.tool = PKInkingTool(.pencil, color: .gray, width: 20)
    #if targetEnvironment(simulator)
    canvasView.drawingPolicy = .anyInput
    #else
    canvasView.drawingPolicy = .default
    #endif
    canvasView.delegate = context.coordinator
    showToolPicker()
    return canvasView
}

完成以上配置后,即可实现单指绘图、双指缩放/平移的Freeform式交互。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 23:17:14