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

如何避免PKCanvasView绘图时背景整体变白?

SwiftUI中PKCanvasView绘制时背景异常变白的解决方法

问题描述

在SwiftUI中通过UIViewRepresentable使用PKCanvasView,需求如下:

  • 画布内容(PKDrawing)区域为白色背景
  • 画布以外的视图区域为灰色背景
  • 画布支持缩放

当前代码初始显示正常,但绘制笔触时,整个屏幕背景会临时变为白色(包括画布外的灰色区域),笔触完成后才恢复正常。尝试将canvasView.backgroundColor设为透明并关闭isOpaque会丢失画布的白色背景,不符合需求。

原代码

import SwiftUI
import PencilKit

struct ContentView: View {
    
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Color(.systemGroupedBackground)
                CanvasView()
            }
        }
    }
}

struct CanvasView: UIViewRepresentable {
    
    func makeUIView(context: UIViewRepresentableContext<CanvasView>) -> PKCanvasView {
        
        let canvasView = PKCanvasView()
        canvasView.drawingPolicy = .anyInput
        canvasView.contentSize = CGSize(width: 1000, height: 1000)
        
//        canvasView.backgroundColor = .clear
//        canvasView.isOpaque = false

        canvasView.minimumZoomScale = 0.5
        canvasView.maximumZoomScale = 4

        return canvasView
    }
    
    func updateUIView(_ view: PKCanvasView, context: UIViewRepresentableContext<CanvasView>) {
        view.setZoomScale(0.5, animated: true)
    }
    
    func makeCoordinator() -> CanvasView.Coordinator {
        return CanvasView.Coordinator(self)
    }
    
    class Coordinator: NSObject, PKCanvasViewDelegate, PKToolPickerObserver {
        
        var parent: CanvasView
        
        init(_ canvasView: CanvasView) {
            self.parent = canvasView
        }
    }
}

问题原因

PKCanvasView在绘制过程中(比如笔触输入时),会临时使用自身的backgroundColor填充整个视图区域,导致原本的灰色背景被覆盖。直接依赖PKCanvasView的背景色来实现画布白色区域的方式会触发这个问题。

解决方案

调整层级结构,分离画布背景与视图背景:

  • 将PKCanvasView的背景设为透明,关闭不透明属性,让下层视图可以透过画布显示
  • 在PKCanvasView底层添加一个与画布contentSize一致的白色视图,作为画布专属背景
  • 保留外层的灰色背景不变

修改后的代码如下:

import SwiftUI
import PencilKit

struct ContentView: View {
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                // 外层灰色背景
                Color(.systemGroupedBackground)
                CanvasView()
            }
        }
    }
}

struct CanvasView: UIViewRepresentable {
    // 统一管理画布尺寸
    private let canvasSize = CGSize(width: 1000, height: 1000)
    
    func makeUIView(context: UIViewRepresentableContext<CanvasView>) -> PKCanvasView {
        let canvasView = PKCanvasView()
        canvasView.drawingPolicy = .anyInput
        canvasView.contentSize = canvasSize
        
        // 关键:将画布背景设为透明,关闭不透明属性
        canvasView.backgroundColor = .clear
        canvasView.isOpaque = false
        
        // 添加仅覆盖画布区域的白色背景视图
        let backgroundView = UIView(frame: CGRect(origin: .zero, size: canvasSize))
        backgroundView.backgroundColor = .white
        canvasView.insertSubview(backgroundView, at: 0)
        
        canvasView.minimumZoomScale = 0.5
        canvasView.maximumZoomScale = 4
        canvasView.delegate = context.coordinator
        
        return canvasView
    }
    
    func updateUIView(_ view: PKCanvasView, context: UIViewRepresentableContext<CanvasView>) {
        // 仅首次加载时设置缩放,避免重复触发动画
        if view.zoomScale == 1.0 {
            view.setZoomScale(0.5, animated: true)
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, PKCanvasViewDelegate {
        var parent: CanvasView
        
        init(_ parent: CanvasView) {
            self.parent = parent
        }
    }
}

关键改动说明

  • 透明画布背景:让PKCanvasView不再自带白色背景,避免绘制时整个视图被临时填充为白色
  • 独立白色背景视图:仅在画布内容区域显示白色,不影响外层灰色背景
  • 优化缩放逻辑:调整缩放触发条件,避免视图每次更新都重复执行动画

这样调整后,绘制笔触时只会在白色画布区域内进行,外层灰色背景不会被临时覆盖,同时保留了画布的白色背景和缩放功能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 11:27:17