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!