简体   繁体   中英

Using PKToolPicker without PKCanvasView

I am trying to use PKToolPicker from PencilKit (iOS/Swift) from a custom view (which is NOT PKCanvasView). The custom view conforms to PKToolPickerObserver . Everything works fine during compile time but I never get to see the PKToolPicker, If I replace my custom view with PKCanvasView, everything works fine!

I am doing this in SwiftUI with UIViewRepresentable (thus First Responder seems a mystery.).

Here is the SwiftUI view in question:

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({$0.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) {
        
    }
}

If I replace myView with PKCanvasView above, the PKToolPicker will be seen.

For the sake of completeness, here is the MyView stub:

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
    }
}

Anyone has succeeded in doing this? Is there some undocumented requirement for adopting PKToolPicker?

Here is simplest demo to show PKToolPicker for any custom UIView in SwiftUI.

Tested with 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()
        }
    }
}

backup

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM