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

PencilKit visionOS附件在模拟器可用,Vision Pro真机无法绘制

Vision Pro Immersive空间中PKCanvasView无法绘制的原因及修复

问题原因

  1. 无碰撞检测:承载画布的RealityKit实体没有添加碰撞组件,Vision Pro的手势射线无法"命中"3D空间中的画布视图,导致输入事件根本传不到PKCanvasView。
  2. 第一响应者失效:Immersive空间的Attachment环境下,直接在makeUIView中调用canvas.becomeFirstResponder()时机不对,画布无法获取输入焦点,接收不到绘制事件。
  3. Canvas实例管理错误:把PKCanvasView作为@State变量从外部传入UIViewRepresentable,视图刷新时容易导致实例状态异常,干扰输入处理逻辑。
  4. 输入适配问题:PKCanvasView默认针对2D触摸/Apple Pencil优化,Vision Pro的3D空间手势需要延迟激活第一响应者,确保视图完全挂载后再处理输入。

修复方案

1. 给Attachment实体添加碰撞体

在RealityView中为承载画布的实体添加碰撞组件,让手势能识别到画布的位置:

struct ImmersiveView: View {
    var body: some View {
        RealityView { content, attachments in
            let entity = Entity()
            entity.position = [0.0, 1.0, -1.0]
            // 添加适配画布尺寸的碰撞盒(可根据实际画布大小调整)
            entity.components.set(CollisionComponent(shapes: [.generateBox(size: [0.6, 0.4, 0.01])]))
            if let attachment = attachments.entity(for: "draw") {
                entity.addChild(attachment)
            }
            content.add(entity)
        } attachments: {
            Attachment(id: "draw") {
                GraffitiView()
            }
        }
    }
}

2. 修正Canvas实例创建与第一响应者逻辑

不在外部用@State保存Canvas实例,改在UIViewRepresentable内部创建,并延迟激活第一响应者:

struct GraffitiView: View {
    @State private var color: Color = .orange
    @State private var pencilType: PKInkingTool.InkType = .crayon
    
    var body: some View {
        DrawingView(pencilType: $pencilType, color: $color)
            .frame(width: 600, height: 400) // 明确画布尺寸,方便碰撞体匹配
    }
}

struct DrawingView: UIViewRepresentable {
  @Binding var pencilType: PKInkingTool.InkType
  @Binding var color: Color

  var ink: PKInkingTool {
    PKInkingTool(pencilType, color: UIColor(color))
  }

  func makeUIView(context: Context) -> PKCanvasView {
    let canvas = PKCanvasView()
    canvas.drawingPolicy = .anyInput
    canvas.tool = ink
    canvas.backgroundColor = .black
    canvas.alwaysBounceVertical = false
    
    // 延迟执行,确保视图已挂载到3D空间
    DispatchQueue.main.async {
        canvas.becomeFirstResponder()
        let toolPicker = PKToolPicker.shared()
        toolPicker.setVisible(true, forFirstResponder: canvas)
        toolPicker.addObserver(canvas)
    }
    
    return canvas
  }

  func updateUIView(_ uiView: PKCanvasView, context: Context) {
    uiView.tool = ink
  }
}

3. 额外优化建议

  • 关闭尺子功能(isRulerActive = false),避免尺子的交互干扰画布绘制。
  • 给GraffitiView设置明确的frame,让碰撞体尺寸和画布实际大小匹配,提升手势命中精度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 00:25:55