Getting started with PencilKit on iOS 13

Introduction

Recently, I’ve released my new drawing app, called Drawland. It’s using Apple’s new drawing framework PencilKit, so in this post I will share some insights and interesting details about this new framework.

Getting started with PencilKit

PencilKit was introduced on WWDC 2019. Although the name might imply differently, PencilKit works great both on iPads with Apple Pencil and iPhones (using the finger). It’s available only on iOS 13 and above.

Why PencilKit?

In a nutshell, PencilKit provides a canvas view, a tool picker (with several useful tools for drawing), as well as PKDrawing object, that you can use for saving / restoring drawings. Of course, all this functionality can be implemented by yourself. I actually had a go with it, in a recentĀ blog post. While that’s a fun thing to try, when you go in production, there are a lot of details that you need to consider to have a fully-fledged drawing app. And with PencilKit, Apple does that for you. It works seamlessly with Apple Pencil and it has high precision and low latency. With PencilKit, instead of re-inventing the wheel, you can focus on your app’s unique features.

pencilkit.PNG

PKCanvasView

The PKCanvasView represents the drawing canvas. It’s scrollable by default. However, in my case, this was not needed, because two canvases were displayed simultaneously (one for the original image to draw and another one for the drawing area).

The PKCanvasView provides several delegate methods, which inform you about several useful events.

    optional func canvasViewDrawingDidChange(_ canvasView: PKCanvasView)
    optional func canvasViewDidFinishRendering(_ canvasView: PKCanvasView)
    optional func canvasViewDidBeginUsingTool(_ canvasView: PKCanvasView)
    optional func canvasViewDidEndUsingTool(_ canvasView: PKCanvasView)

The canvasViewDrawingDidChange method is called whenever there’s a change in the canvas. It’s useful if you want to mark the drawing as modified, and maybe save it. In my case, it was also the event that triggered the image comparison code.

The canvasViewDidFinishRendering is called when the canvas view is rendered. If you have a more complex drawing, it may take a second, but the drawing is displayed part by part, so this looks good.

The other two delegate methods are called when the user starts and finishes the tool for drawing.

Integrating PKCanvasView in your app is very easy. You can do it either via storyboard or in code.

let canvas = PKCanvasView(frame: bounds)
view.addSubview(canvas)
canvas.tool = PKInkingTool(.pen, color: .black, width: 30)

If you do it via storyboard, make sure to add a regular UIView and then change its class to be PKCanvasView.

PKDrawing

The PKDrawing object represents the actual drawing on the canvas. You can get the frame of the drawing in the canvas. You can also easily serialise / deserialise it, to store it locally or on a server (in my case that was Firebase). Since the original drawings were drawn on one iPad, but displayed on many different devices, we had to re-scale and translate the drawing in many different canvas sizes. For this, the possibility to use CGAffineTransforms on the drawings proved to be very useful. Apart from that, you can append other drawings to the drawing programatically.

let factor = min(scaleX, scaleY)
let transform = CGAffineTransform(scaleX: factor, y: factor)
let drawing = pkDrawing.transformed(using: transform)

Another useful feature from PKDrawing (which I’ve used extensively), is the possibility to get the current UIImage from the drawing.

private func image(from canvas: PKCanvasView) -> UIImage {
    let drawing = canvas.drawing
    let visibleRect = canvas.bounds
    let image = drawing.image(from: visibleRect, scale: UIScreen.main.scale)
    return image
}

PKToolPicker

The PKToolPicker is a UI component that contains the tools for your drawing. On iPads, it’s floating over all views, while on iPhones it’s a view on the bottom of the screen. On iPads, it contains undo/redo functionality, while on iPhones you would need to add them by yourself.

To connect the PKToolPicker with the canvas view, you would need to write the following lines of code:

if let window = parent?.view.window,
   let toolPicker = PKToolPicker.shared(for: window) {
     toolPicker.setVisible(true, forFirstResponder: canvasView)
     toolPicker.addObserver(canvasView)
     toolPicker.addObserver(self)
     canvasView.becomeFirstResponder()

The PKToolPicker consists of several useful tools for drawing.

  • PKInkingTool – Contains the tools for drawing. It consists of a pen, marker or pencil.
  • PKEraserTool – this is the brush that deletes parts or all of your drawing. It can be object based (an entire object is deleted) or pixel based (when you want to remove certain pixels).
  • PKLassoTool – you can select a drawing area and move it around.
  • Ruler – for drawing straight lines.
  • Color picker – for picking a colour for your inking tool.
  • Undo/Redo functionality (only on iPad)

Limitations

However, with so many things coming out of the box, you don’t have a lot of flexibility for doing custom things. Several things I’ve encountered are:

  • it’s hard to customise the tool picker
  • you can’t get a list of all strokes that the drawing is consisted of
  • you get only a data representation of the drawing

Conclusion

PencilKit is a great new framework, which provides a lot of drawing functionality out-of-the-box. It’s a crucial part of my new app, Drawland. It saved me a lot of time and energy to focus on the parts that are specific to my app. It’s easy to get started and to integrate it in an app.

If you want to use it with SwiftUI, you can write your own UIViewRepresentable wrapper from UIKit to SwiftUI.

What are your thoughts on PencilKit? Have you tried it already? Leave your comments in the area below.

Good starting point with PencilKit is Apple’s reference code. If you want to see PencilKit in action, try out Drawland, by downloading it on the store.

About martinmitrevski

Software Engineer | Book Author | International Speaker. I love exploring and building things.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s