SoFunction
Updated on 2025-04-11

How to develop simple hand-drawn application examples in iOS

Develop a simple iOS hand-drawn app.

Collect points, draw shapes, color the shapes, and present them to the user, it seems to be finished

The framework is Quartz2D

1. Collect points

First, there is an interface UIView, which uses this interface to listen to user's gestures and collect points

  • User presses finger

location(in, get coordinates in the artboard from the touch event

var lastPoint = 


override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
 guard let touch =  else {
 return
 }
 // ...
 lastPoint = (in: view)
 }
  • User moves fingers
 override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
  // ...
 }
  • User lifts his finger
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
  // ...
 }
 

2. Draw the shape and color the shape

Create a drawing context UIGraphicsGetCurrentContext,

Use the collected point line

What the user draws is not a continuous curve, but a number of line segments are spliced ​​together.

func drawLine(from fromPoint: CGPoint, to toPoint: CGPoint) {
 UIGraphicsBeginImageContext()
 guard let context = UIGraphicsGetCurrentContext() else {
 return
 }
 // ...
 // Draw (to: fromPoint)
 (to: toPoint)
 
 (.round)
 (.normal)
 (brushWidth)
 ()
 
 ()
 // ...
 
 UIGraphicsEndImageContext()
 }

3. Present to the user

The UIView used in the first step is UIImageView.

  • Drawing is to draw a small piece, take out the drawn picture, assign it to the UIImageView, and we will see it
  • Continuous drawing is to draw a small piece, take out the drawn picture, assign it to the UIImageView, and save the latest picture with variables.

Then draw, draw the image variable just now, then draw a small paragraph, take out the drawn picture, assign it to the UIImageView, and save the latest picture with the variable

func drawLine(from fromPoint: CGPoint, to toPoint: CGPoint) {
 UIGraphicsBeginImageContext()
 guard let context = UIGraphicsGetCurrentContext() else {
 return
 }
 ?.draw(in: )
 
 // Draw... 
  = UIGraphicsGetImageFromCurrentImageContext()
 
 UIGraphicsEndImageContext()
}

4. Brush settings

Modify brush color and thickness

func drawLine(from fromPoint: CGPoint, to toPoint: CGPoint) {
 UIGraphicsBeginImageContext()
 guard let context = UIGraphicsGetCurrentContext() else {
 return
 }
 
 // ...
 
 (.normal)
 
 // Adjust the color (brushWidth)
 // Adjust the thickness ()
 // ...
}

Brush turns eraser

  • Method 1: Adjust the color of the brush to the color of the painting board, and it becomes an eraser
  • Method 2,

Make the color of the brush transparent.

Change the color mixing mode of the drawing context

It's an eraser

  switch type {
  case .pencil, .none:
   (.color)
  case .eraser:
   (15)
   ()
   (.clear)
  }

5. Subsequent

More features:

Add text input function,

Requires a text box control UITextField, UITextView

Text box controls can generally be dragged.

The text box is placed on the canvas and dragged out the canvas, which is a problem.

At this time, a boundary detection needs to be done

Performance optimization:

General performance optimization is the execution time of the printing function

When the size of the canvas is 1366 X 7700 (iPad Pro + UIScrollView), the canvas is very large.

Draw all and take out the picture, which consumes a lot of performance

 ?.draw(in: )
 // ...
 
  = UIGraphicsGetImageFromCurrentImageContext()

Draw once, it takes about 0.07 seconds.

 let t = Date()
 ()
 if #available(iOS 13.0, *) {
  let span = (to: Date())
  print(span)
 }

We expect a FPS of 60, and the calculation time per frame is 0.016, so we can call this method frequently and get stuck very hard.

The previous method was to draw a point, a point

Move it and draw it once

 override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
 guard let touch =  else {
  return
 }
 swiped = true
 let currentPoint = (in: view)
 drawLine(from: lastPoint, to: currentPoint)
 lastPoint = currentPoint
 }

Draw a line, func touchesMoved() , which can usually be triggered 30 to 60 times, and there are many points collected and the lines are soft.

At this time, the performance-consuming method is frequently called.

Only trigger 6 times, draw a paragraph and only collect 6 points. At normal hand speed, draw a polygon

This can be optimized, and the collection and drawing of points can be separated.

Use a Timer to draw every 0.15 seconds

Originally, the collection point was a CGPoint, but now the collection point is a [CGPoint]

  • Originally, I drew the image before, connected a line, updated the image variable and presented it

n dots, n times full-frame drawing

  • Now draw the previous image once, connect multiple lines, update the image variables and render

n dots, draw the full picture board once

A performance-consuming method, call less, it's right

 ?.draw(in: )
 // ...
 
  = UIGraphicsGetImageFromCurrentImageContext()

The code for the first 4 points is shown in github

It needs to be sorted out later, tbd

Summarize

This is the end of this article about how to develop simple hand-drawn applications on iOS. For more related content on developing hand-drawn applications on iOS, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!