I'm trying to integrate Apple Pencil with a WKWebView.
Desired behavior:
- Using pencil allows you to draw on the webpage with all the fancy PencilKit integrations (PKToolPicker, etc)
- Using fingers allows you to scroll through the webpage, and the scrolling is synced to the webview.
TAKE 2
So after spending a bit more time with this, I've arrived at an extremely hacky solution, and I don't actually like the solution:
- Create a
WKWebView
and a transparentPKCanvasView
on top of it. - Override the
hitTest
of the `PKCanvasView to always return nil. - Add the
drawingGestureRecognizer
of the PKCanvasView to theWKWebView
- Make sure that
drawingGestureRecognizer.allowedTouchTypes = [NSNumber(value: UITouch.TouchType.pencil.rawValue)]
is set for thePKCanvasView
This approach works but it removes a ton of flexibility for the implementation.
TAKE 1
So far I've tried two approaches:
Selectively cancel user input on the canvas when I detect it's coming from a finger. This didn't work because there was no way for me to detect this before the event was consumed by the view.
Create a transparant superview, and manually call touchesBegan/touchesMoved/touchesEnded for the PKCanvasView and WKWebView when I did my detection. Unfortunately, this didn't work either as calling those methods didn't do anything.
This is some basic code I have so far:
struct SUICanvasView: UIViewControllerRepresentable {
let url: URL?
func makeUIViewController(context: Context) -> ZRCanvasReader {
let canvasReader = ZRCanvasReader()
canvasReader.openUrl(url: url)
return canvasReader
}
func updateUIViewController(_ uiViewController: ZRCanvasReader, context: Context) {
}
typealias UIViewControllerType = ZRCanvasReader
}
class ZRCanvasReader: UIViewController {
lazy var canvas: PKCanvasView = {
let v = PKCanvasView()
v.isOpaque = false
v.backgroundColor = .clear
return v
}()
lazy var toolPicker: PKToolPicker = {
let toolPicker = PKToolPicker()
return toolPicker
}()
lazy var webView: WKWebView = {
let prefs = WKWebpagePreferences()
prefs.allowsContentJavaScript = true
let config = WKWebViewConfiguration()
config.defaultWebpagePreferences = prefs
let webview = WKWebView(frame: .zero, configuration: config)
return webview
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(webView)
view.addSubview(canvas)
webView.frame = view.frame
canvas.frame = view.frame
toolPicker.addObserver(canvas)
toolPicker.setVisible(true, forFirstResponder: canvas)
}
func openUrl(url: URL?) {
guard let loadingUrl = url else {
return
}
let request = URLRequest(url: loadingUrl)
webView.load(request)
}
}