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

无法切换PKToolPicker工具:PencilKit绘图工具切换异常求助

解决PencilKit PKToolPicker无法切换工具的问题

问题根源

你这段代码里有几个关键问题,导致工具切换失效:

  • 每次点击按钮都会新建PKToolPicker实例,旧的picker直接被丢弃,无法保留工具选择状态
  • 未将PKToolPicker保存为类属性,实例用完就被释放,无法和PKCanvasView正常交互
  • 没有将ViewController设置为PKToolPicker的观察者,接收不到工具变化的通知

修复后的完整代码

class ViewController: UIViewController, PKToolPickerObserver {
    
    private var canvasView: PKCanvasView!
    private var toolPicker: PKToolPicker! // 持久保存picker引用,避免重复创建
    @IBOutlet weak var imgView: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupNavigationButton()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        setupCanvasView()
        setupImageFromDocuments()
    }
    
    private func setupNavigationButton() {
        let pencilButton = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
        pencilButton.addTarget(self, action: #selector(showPKToolKit), for: .touchUpInside)
        pencilButton.setImage(UIImage(systemName: "pencil.tip"), for: .normal)
        pencilButton.tintColor = .tintColor
        
        navigationItem?.rightBarButtonItem = UIBarButtonItem(customView: pencilButton)
    }
    
    private func setupCanvasView() {
        canvasView = PKCanvasView(frame: imgView.bounds)
        canvasView.isOpaque = false
        canvasView.drawingPolicy = .anyInput // 提前设置绘图策略
        // 将canvas添加到imgView上层,确保绘制内容显示在图片之上
        imgView.addSubview(canvasView)
        // 使用Auto Layout替代固定frame,适配屏幕旋转与不同尺寸
        canvasView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            canvasView.topAnchor.constraint(equalTo: imgView.topAnchor),
            canvasView.leadingAnchor.constraint(equalTo: imgView.leadingAnchor),
            canvasView.trailingAnchor.constraint(equalTo: imgView.trailingAnchor),
            canvasView.bottomAnchor.constraint(equalTo: imgView.bottomAnchor)
        ])
        
        // 使用全局共享的PKToolPicker实例,而非每次新建
        toolPicker = PKToolPicker.shared()
        toolPicker.addObserver(self)
        toolPicker.addObserver(canvasView)
    }
    
    private func setupImageFromDocuments() {
        let fileManager = FileManager.default
        guard let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        
        do {
            let urls = try fileManager.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil)
            guard !urls.isEmpty else {
                print("Documents目录为空")
                return
            }
            let data = try Data(contentsOf: urls[0])
            imgView.image = UIImage(data: data)
        } catch {
            print("加载图片失败: \(error.localizedDescription)")
        }
    }
    
    @objc func showPKToolKit() {
        canvasView.becomeFirstResponder()
        toolPicker.setVisible(true, forFirstResponder: canvasView)
        toolPicker.reloadAllTools() // 确保工具列表正常加载
    }
    
    // 可选:监听工具切换事件,自定义后续逻辑
    func toolPickerSelectedToolDidChange(_ toolPicker: PKToolPicker) {
        // 这里可以添加工具切换后的处理代码
    }
}

关键修改说明

  1. 添加持久化toolPicker属性:使用PKToolPicker.shared()获取全局实例,避免重复创建,保证工具选择状态的连贯性
  2. 提前初始化Canvas与Picker关联:在viewDidAppear中完成canvas和picker的绑定,而非点击按钮时才临时创建
  3. 调整Canvas层级与适配方式:将canvas添加到imgView上层确保绘制内容可见,用Auto Layout替代固定frame,适配不同屏幕场景
  4. 正确设置观察者:将ViewController和CanvasView都添加为picker的观察者,保证交互逻辑正常运行
  5. 提前配置绘图策略:在canvas初始化阶段就设置drawingPolicy,无需在点击按钮时重复操作

内容的提问来源于stack exchange,提问作者Gopalakrishnan G.S.R

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 08:35:40