11

I'd like to be able to load a PNG file into a PKCanvasView to be able to draw on and erase parts of it. Is there a way to accomplish this?

tomaculum
  • 547
  • 4
  • 15
rawbee
  • 2,946
  • 3
  • 18
  • 22

4 Answers4

4

First, put your UIImageView behind PKCanvasView, then set the PKCanvasView opaque to false, and color to clear.

Then in PKCanvasViewDelegate:

func viewForZooming(in scrollView: UIScrollView) -> UIView? {
    return YOUR_IMAGEVIEW
}

func scrollViewDidZoom(_ scrollView: UIScrollView) {

    let offsetX: CGFloat = max((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0)
    let offsetY: CGFloat = max((scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5, 0.0)
    YOUR_IMAGEVIEW.frame.size = CGSize(width: self.view.bounds.width * scrollView.zoomScale, height: self.view.bounds.height * scrollView.zoomScale)
    YOUR_IMAGEVIEW.center = CGPoint(x: scrollView.contentSize.width * 0.5 + offsetX, y: scrollView.contentSize.height * 0.5 + offsetY)

}

As apple said, putting your imageView in viewForZooming is enough, but It doesn't work. So I added above codes in scrollViewDidZoom and it just works as it is supposed to be.

4

I can't find any official documentation about this, but I make it work by adding a UIImageView as subview of first subview of PKCanvasView. Zooming is also working perfectly by setting both .maximumZoomScale=1 and .minimumZoomScale=5

But notice this might not work in the future as Apple might change their implementation of PKCanvasView

Here's the sample code for SwiftUI

    func makeUIView(context: Context) -> UIView {
        let view = PKCanvasView()
        ...
        ...
        view.backgroundColor = .clear
        view.isOpaque = false
        view.maximumZoomScale = 5
        view.minimumZoomScale = 1

        let imageView = UIImageView(image: UIImage(named: "NameOfImage"))
        let contentView = Tool.getContentViewFromPkCanvasView(view)
        contentView.addSubview(imageView)
        contentView.sendSubviewToBack(imageView)
        return view
    }
class Tool{
    static func getContentViewFromPkCanvasView(_ view: UIView) -> some UIView {
        return view.subviews[0]
    }
}
Po-Wen Kao
  • 41
  • 3
  • This is clever, but unfortunately, it still just acts like a background image—you're not able to erase for example. – rawbee Apr 27 '20 at 00:54
  • 1. this probably (i.e. most definitely) is a bad idea because apple can change the canvas view's internal structure at any time, in which case this would stop working (and would, in the worst case, crash); 2. there's no need to use `some UIView` as the return type. `subviews` is an `[UIView]`, so the type is fixed and the `some` doesn't do anything. (also, `UIView` is not generic in the first place) – lukas Aug 27 '21 at 13:57
3

Use an UIImageView and put it behind PKCanvasView, then set the PKCanvasView opaque to false, and color to clear. Draw on it is fine, but erase is not possible.

Lim Thye Chean
  • 8,704
  • 9
  • 49
  • 88
0

Use setDrawing of PKCanvasView

https://developer.apple.com/documentation/pencilkit/pkcanvasview/3229950-drawing

See 26:53 duration of Session video 221

See 26:53 of Session video 221

guhan0
  • 666
  • 6
  • 19