How to make a simple 2D drawing app in Swift

UIKit has powerful tools and API that enable 2D drawing, which comes in handy often when we need to draw fast hand sketches and drawings.

Many apps in Apple store are built to empower finger drawing, and your app can start to become the next one 🙂

In this tutorial, I gonna show you the simple techniques behind 2D drawing and how to implement them to make your own drawing app.

At the end of this tutorial, you will have a neat board in which you can draw your custom sketches and save them to the Photo Library as images.

First, download the starter project here.

Open up the project and select Main.storyboard file from the Project navigator view. The screen is composed of two buttons located in the navigation bar, the left button will erase the drawing and reinitialise a clean board, while the right button will save the drawing to the Photo Library of your device. The rest of the screen is a white board in which you gonna draw your sketches.

Cool, now place to the code. Select ViewController.swift from the Project navigator and take a look at the code already put in there. You may notice that I have already hook up two action methods and a UIImageView object to the code. The ‘saveImage’ method is bound to the right button and the ‘undoDrawing’ method is bound to the left button, while the ‘imageView’ property is actually a reference for the white board you gonna draw in.

Copy the following vars declarations just under the ViewController class name:
a

var lastPoint:CGPoint!
var isSwiping:Bool!
var red:CGFloat!
var green:CGFloat!
var blue:CGFloat!

The ‘lastPoint’ var will store the coordinate (x,y) of the touch in the screen, so that UIKit knows from where it should start and where it should stop drawing. You also declared a bool variable, this is a flag to recognise whether you are swiping your finger or it’s just a one-touch on the screen. The rest of the variables are float values for the drawing main color.

Before you go further, let’s initialise the color code vars. Copy the following code inside the viewDidLoad method:

 red   = (0.0/255.0)
 green = (0.0/255.0)
 blue  = (0.0/255.0)

The generated code above is black, feel free to change it to whatever color you feel confortable with.

Now, we need to implement some touches handler methods in order to respond to finger gestures and draw properly.

Start by placing the following code before the closing bracket of the class:

override func touchesBegan(touches: Set,
     withEvent event: UIEvent?){
      isSwiping    = false
      if let touch = touches.first{
         lastPoint = touch.locationInView(imageView)
      }
}

The code above will run as soon as you touch the screen, it will set the flag ‘isSwiping’ to false assuming you are just typing a single dot in the screen. Also, it will store the last touched point coordinate in the board.

Next, copy the following method:

  override func touchesMoved(touches: Set,
        withEvent event: UIEvent?){
            
            isSwiping = true;
            if let touch = touches.first{
                let currentPoint = touch.locationInView(imageView)
                UIGraphicsBeginImageContext(self.imageView.frame.size)
                self.imageView.image?.drawInRect(CGRectMake(0, 0, self.imageView.frame.size.width, self.imageView.frame.size.height))
                CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y)
                CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y)
                CGContextSetLineCap(UIGraphicsGetCurrentContext(),kCGLineCapRound)
                CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 9.0)
                CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(),red, green, blue, 1.0)
                CGContextStrokePath(UIGraphicsGetCurrentContext())
                self.imageView.image = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                lastPoint = currentPoint
            }
    }

The method above will start running as soon as you hold your finger and move it around, and will run continuously as long as your finger is moving. This is the right place to start drawing lines. First, you set the flag ‘isSwiping’ to true so that the app will recognise it should draw continuous dots instead of a single point. Then the code will continuously catch the current point as you move and draw a line (continuous dots) to reach it in the screen. This way, you will notice UIKit is following your finger movement with a black line as you swipe around in the board.

Lastly, we need to notify the controller each time you release your finger off the screen. This is the right place to detect a single dot touch and draw it. To do so, copy the following code below:

    override func touchesEnded(touches: Set,
        withEvent event: UIEvent?){
            if(!isSwiping) {
               UIGraphicsBeginImageContext(self.imageView.frame.size)
                self.imageView.image?.drawInRect(CGRectMake(0, 0, self.imageView.frame.size.width, self.imageView.frame.size.height))
                CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound)
                CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 9.0)
                CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0)
                CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y)
                CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y)
                CGContextStrokePath(UIGraphicsGetCurrentContext())
                self.imageView.image = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
            }
}

As you may notice, the code above is similar to the code in the ‘touchesMoved’ method, except that it will run after you release the mouse/finger touch, and also after checking whether the ‘isSwiping’ flag is set to false (which means there was a single touch on the screen).

So far so good. Build and run the project and try to play around with your finger or mouse pointer, if you run on the simulator.

Drawing with UIKit

To finish up with your drawing app, let’s implement the two action methods bound to the left and right buttons in the navigation bar. Locate the ‘undoDrawing’ method and place the following statement inside:

self.imageView.image = nil

This will reinitialise the imageView’s image property by setting it to nil and hence clearing the board for new drawings.

Next, place the following code inside the ‘saveImage’ method:

if self.imageView.image == nil{
   return
}
UIImageWriteToSavedPhotosAlbum(self.imageView.image!,self, Selector("image:withPotentialError:contextInfo:"), nil)

UIImageWriteToSavedPhotosAlbum is a UIKit API that save an image to the camera roll album. You just pass the image object and a selector method to call after the saving operation is completed. Copy the following code before the closing bracket of the class:

func image(image: UIImage, withPotentialError error: NSErrorPointer, contextInfo: UnsafePointer<()>) {
        UIAlertView(title: nil, message: "Image successfully saved to Photos library", delegate: nil, cancelButtonTitle: "Dismiss").show()
}

That’s it, build and run the app. Draw, erase, draw again and save to the Photo Library. Well, enjoy your work 🙂

As usual, you can download the completed project here.

You can enhance the project by implementing a color palette, automatic shapes drawings, etc. Let me know your thoughts in the comments below, I’d love to hear from you!


Discover more from SweetTutos

Subscribe to get the latest posts sent to your email.

Malek
Software craftsman with extensive experience in iOS and web development.