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

SwiftUI中UIViewRepresentable如何更新PKCanvasView的图片?

PencilKit画布切换图片不更新的问题修复

问题核心

点击Next按钮切换图片时,PKCanvasView无法显示新图片,根源在于:

  • UIViewRepresentable的makeUIView仅执行一次,初始图片仅在此时被添加到画布
  • updateUIView中未处理图片更新逻辑,旧图片视图始终留在画布上
  • 复用ViewModel中的PKCanvasView实例,导致旧绘图和子视图残留

修复方案

1. 修改DrawingView,在updateUIView中处理图片更新

将图片添加逻辑抽为独立方法,在初始化和视图更新时都调用,同时清除旧的图片视图:

struct DrawingView: UIViewRepresentable {
    @Binding var imageData: Data
    @Binding var editable: Bool
    @Binding var toolPicker: PKToolPicker
    var rect: CGSize
    
    func makeUIView(context: Context) -> PKCanvasView {
        let canvas = PKCanvasView()
        canvas.drawingPolicy = .anyInput
        canvas.backgroundColor = .clear
        canvas.isOpaque = false
        
        // 初始化加载第一张图片
        updateBackgroundImage(for: canvas)
        
        toolPicker.setVisible(true, forFirstResponder: canvas)
        toolPicker.addObserver(canvas)
        canvas.becomeFirstResponder()
        
        return canvas
    }

    func updateUIView(_ uiView: PKCanvasView, context: Context) {
        // 更新编辑权限
        uiView.drawingPolicy = editable ? .anyInput : .pencilOnly
        uiView.isUserInteractionEnabled = editable
        toolPicker.setVisible(editable, forFirstResponder: uiView)
        toolPicker.addObserver(uiView)
        
        // 切换图片时更新背景
        updateBackgroundImage(for: uiView)
    }
    
    // 复用的图片更新逻辑
    private func updateBackgroundImage(for canvas: PKCanvasView) {
        // 清除旧的图片视图
        canvas.subviews.first?.subviews.removeAll(where: { $0 is UIImageView })
        
        // 添加新图片
        guard let image = UIImage(data: imageData) else { return }
        let imageView = UIImageView(image: image)
        imageView.frame = CGRect(x: 0, y: 0, width: rect.width, height: rect.height)
        imageView.contentMode = .scaleAspectFit
        imageView.clipsToBounds = true
        
        if let containerView = canvas.subviews.first {
            containerView.addSubview(imageView)
            containerView.sendSubviewToBack(imageView)
        }
    }
}

2. 修改Canvas视图,移除外部画布的绑定

不再复用ViewModel中的PKCanvasView实例,改为在DrawingView内部创建新画布:

struct Canvas: View {
    @EnvironmentObject var viewModel: ViewModels.ImageDataViewModel
    @Binding var editable: Bool
    
    var body: some View {
        VStack {
            GeometryReader { proxy in
                let size = proxy.frame(in: .global).size
                DispatchQueue.main.async {
                    if viewModel.rect == .zero {
                        viewModel.rect = proxy.frame(in: .global)
                    }
                }
                DrawingView(
                    imageData: $viewModel.imageData,
                    editable: $editable,
                    toolPicker: $viewModel.toolPicker,
                    rect: size
                )
            }
        }
    }
}

3. 确保ViewModel的imageData同步更新

点击Next按钮切换图片时,ViewModel需要将imageData同步更新为当前选中图片的Data:

// 在ImageDataViewModel中,切换currentImageData时同步更新imageData
func removeEditedImage(imageId: String) {
    // 原有移除图片的逻辑...
    if let nextImage = currentImageData {
        imageData = nextImage.data // 假设currentImageData包含data字段
    }
}

关键改进点

  • 每次切换图片时先清除画布上的旧图片视图,避免图片叠加
  • 将图片更新逻辑抽离,保证初始化和视图更新时都能正确加载图片
  • 不再复用外部画布实例,避免旧绘图和状态残留

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:44:55