Maps Under Pencil

Start by launching a new Single View Application in your Xcode.

Our first step will be to put our MKMapView under the PKCanvasView , so that we can draw over it!

Setting the MKMapView

It’s easy! You just need to import MapKit and add MKMapView in your View Controller. The following code does it without a storyboard.

var mapView = MKMapView(frame: CGRect(x: 0, y: 60, width: view.frame.size.width, height: view.frame.size.height - 60)) self.view.addSubview(mapView)

Setting the PKCanvasView

let canvasView = PKCanvasView(frame: .zero)

canvasView.translatesAutoresizingMaskIntoConstraints = false

canvasView.isOpaque = false

view.addSubview(canvasView)



canvasView.backgroundColor = .clear



NSLayoutConstraint.activate([

canvasView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 40),

canvasView.bottomAnchor.constraint(equalTo: view.bottomAnchor),

canvasView.leadingAnchor.constraint(equalTo: view.leadingAnchor),

canvasView.trailingAnchor.constraint(equalTo: view.trailingAnchor),

])

We’ve set the background color of the Canvas to transparent so that the Map underneath it is visible.

Setting the PKToolPicker

The following code adds the PencilKit ToolPicker for you.

override func viewDidAppear(_ animated: Bool) {

super.viewDidAppear(animated) guard let window = view.window,

let toolPicker = PKToolPicker.shared(for: window) else { return } toolPicker.setVisible(true, forFirstResponder: canvasView)

toolPicker.addObserver(canvasView)

canvasView.becomeFirstResponder()

}

Dragging the Map when it’s beneath the Canvas isn’t a tricky scenario. All we need to do is allow passing touches from the CanvasView to the views underneath.

So we’ll keep a toggle button which allows alternating dragging and drawing. In the first case, we pass the touches from the CanvasView and in the second case, we don’t!

We override the point function present inside the PKCanvasView class in the extension below:

extension PKCanvasView{

override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool {

return DragOrDraw.disableDrawing

}

} class DragOrDraw{

static var disableDrawing = true

}

disableDrawing is a boolean flag that can toggle map dragging and pencil drawing from the NavigationBar because both can't coexist at the same time.

Setting up navigationBar

var toggleDrawItem : UIBarButtonItem!



var disableDraw : Bool = false



func setNavigationBar() { let previewItem = UIBarButtonItem(title: "Preview", style: .done, target: self, action: #selector(preview))



let clearItem = UIBarButtonItem(title: "Clear", style: .plain, target: self, action: #selector(clear)) toggleDrawItem = UIBarButtonItem(title: "Drag", style: .plain, target: self, action: #selector(dragDrawToggler)) let navigationItem = UINavigationItem(title: "")

navigationItem.rightBarButtonItems = [clearItem,previewItem]

navigationItem.leftBarButtonItem = toggleDrawItem

navigationBar = UINavigationBar(frame: .zero)

navigationBar?.isTranslucent = false



navigationBar!.setItems([navigationItem], animated: false) navigationBar!.translatesAutoresizingMaskIntoConstraints = false

view.addSubview(navigationBar!) navigationBar!.backgroundColor = .clear NSLayoutConstraint.activate([

navigationBar!.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),

navigationBar!.heightAnchor.constraint(equalToConstant: 60),

navigationBar!.leadingAnchor.constraint(equalTo: view.leadingAnchor),

navigationBar!.trailingAnchor.constraint(equalTo: view.trailingAnchor),

]) }

Now that the UI components are section, it’s time to convert the PencilKit drawings to Map Images.