在没有 PKCanvasView 的情况下使用 PKToolPicker

Using PKToolPicker without PKCanvasView

我正在尝试从自定义视图(不是 PKCanvasView)中使用 PencilKit (iOS/Swift) 中的 PKToolPicker。自定义视图符合PKToolPickerObserver。编译期间一切正常,但我从来没有看到 PKToolPicker!如果我用 PKCanvasView 替换自定义视图,一切正常!

我正在使用 UIViewRepresentable 在 SwiftUI 中执行此操作(因此 First Responder 似乎是个谜!)。

这是有问题的 SwiftUI 视图:

struct PencilKitView: UIViewRepresentable {
    typealias UIViewType = myView
    
    let coordinator = Coordinator()
    
    class Coordinator: NSObject, PKToolPickerObserver {
        
        func toolPickerSelectedToolDidChange(_ toolPicker: PKToolPicker) {
            // some code
        }
        func toolPickerVisibilityDidChange(_ toolPicker: PKToolPicker) {
            // some code
        }
        
    }
    func makeCoordinator() -> PencilKitView.Coordinator {
        return Coordinator()
    }
    
    func makeUIView(context: Context) -> myView {
        let canvasView = myView()
        
        canvasView.isOpaque = false
        canvasView.backgroundColor = UIColor.clear
        canvasView.becomeFirstResponder()

        if let window = UIApplication.shared.windows.filter({[=10=].isKeyWindow}).first,
            let toolPicker = PKToolPicker.shared(for: window) {
            toolPicker.addObserver(canvasView)
            toolPicker.addObserver(coordinator)
            toolPicker.setVisible(true, forFirstResponder: canvasView)
        }
        return canvasView
    }
    
    func updateUIView(_ uiView: myView, context: Context) {
        
    }
}

如果我将上面的 myView 替换为 PKCanvasView,就会看到 PKToolPicker。

为了完整起见,这里是 MyView 存根:

class myView: UIScrollView, PKToolPickerObserver {
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    public func toolPickerVisibilityDidChange(_ toolPicker: PKToolPicker) {
        /// some code
    }
    
    public func toolPickerSelectedToolDidChange(_ toolPicker: PKToolPicker) {
        /// some code
    }
    
    public func toolPickerIsRulerActiveDidChange(_ toolPicker: PKToolPicker) {
        /// some code
    }
    
    public func toolPickerFramesObscuredDidChange(_ toolPicker: PKToolPicker) {
        /// some code
    }
}

有人成功过吗?采用 PKToolPicker 是否有一些未记录的要求?

这里是展示 SwiftUI 中任何自定义 UIView 的 PKToolPicker 的最简单的演示。

测试 Xcode 11.4 / iOS 13.4

struct ToolPickerDemo: View {
    @State private var showPicker = false
    var body: some View {
        Button("Picker") { self.showPicker.toggle() }
            .background(ToolPickerHelper(isActive: $showPicker))
    }
}

class PickerHelperView: UIView {
    override var canBecomeFirstResponder: Bool { true }
}

struct ToolPickerHelper: UIViewRepresentable {
    @Binding var isActive: Bool

    func makeUIView(context: Context) -> PickerHelperView {
        PickerHelperView()
    }

    func updateUIView(_ uiView: PickerHelperView, context: Context) {
        guard let window = uiView.window else { return }

        let picker = PKToolPicker.shared(for: window)
        picker?.setVisible(isActive, forFirstResponder: uiView)

        DispatchQueue.main.async {
            uiView.becomeFirstResponder()
        }
    }
}