Here's a great article on how to get a smooth signature on Android:smoother Signatures: https://corner.squareup.com/2012/07/ Smoother-signatures.html, but I didn't find an article on how to write on iOS. So what exactly does it take to get a user's signature on an iOS device?
Although I didn't find any articles about getting a signature, I already have a well-implemented app on the App Store. Paperby: Http://www.fiftythree.com/paper is an ipad app for painting, it has a beautiful and sensitive brush, which is what I want to pursue the user experience.
The code can be obtained from here: signaturedemo:https://github.com/jharwig/ppssignatureview
Connecting dots into lines
The simplest way is to get the touch points in turn and connect them in a straight line.
The path is created in the initialization method of the UIView subclass and the gesture Recongnizer used to capture the touch event.
// Create a path to connect linespath = [UIBezierPath bezierPath];// Capture touchesUIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];pan.maximumNumberOfTouches = pan.minimumNumberOfTouches = 1;[self addGestureRecognizer:pan];
The captured Pan event location data is added sequentially to the Bezier path, which is connected to a line.
- (void)pan:(UIPanGestureRecognizer *)pan { CGPoint currentPoint = [pan locationInView:self]; if (pan.state == UIGestureRecognizerStateBegan) { [path moveToPoint:currentPoint]; } else if (pan.state == UIGestureRecognizerStateChanged) [path addLineToPoint:currentPoint]; [self setNeedsDisplay];}
Draw a trajectory
- (void)drawRect:(CGRect)rect{ [[UIColor blackColor] setStroke]; [path stroke];}
Drawing a letter J in this way exposes some problems.
When the signature is slow, iOS can capture enough touch location information to make the connected lines look less obvious. But when the fingers move fast, there is trouble.
Building Advanced Gesture recognizers:https://developer.apple.com/videos/play/wwdc2012/233/, introduced at the 2012 Apple Developer Conference, mentions that It is possible to solve this problem with maths.
Quadratic Bezier curve
We need to use the two Bezier curves to connect the touch points instead of the straight line, and refer to the Apple Developer Conference video given above (around 42:15). When connecting two Bezier curves, touch points should be treated as control points, while the midpoint is the corresponding start and end point.
Adding two times the Bezier curve to the previous code requires the last touch information, so we add an instance variable to store itCGPoint previousPoint;
Write a method to calculate the midpoint of 2 points
static CGPoint midpoint(CGPoint p0, CGPoint p1) { return (CGPoint) { (p0.x + p1.x) / 2.0, (p0.y + p1.y) / 2.0 };}
Update gesture processing, replace the previous direct connection processing with two Bezier curves
- (void)pan:(UIPanGestureRecognizer *)pan { CGPoint currentPoint = [pan locationInView:self]; CGPoint midPoint = midpoint(previousPoint, currentPoint); if (pan.state == UIGestureRecognizerStateBegan) { [path moveToPoint:currentPoint]; } else if (pan.state == UIGestureRecognizerStateChanged) { [path addQuadCurveToPoint:midPoint controlPoint:previousPoint]; } previousPoint = currentPoint; [self setNeedsDisplay];}
Without writing a lot of code, we saw a big change. The edges are missing, but it seems a bit tedious as a signature. Each curve is equal width, and the signature effect that is checked out with a real pen is violated.
Variable Brush width
The brush width should vary based on the speed of the signature, so the signature looks natural. Uipangesturerecognizer has a Velocityinview method to return the speed of the current touch point.
To draw the width of the change, I use the OpenGL ES surface subdivision instead to convert the brush to a triangular sequence (OpenGL supports draw lines, but iOS does not support drawing smooth, variable-width lines). Quadratic Bezier points need to be recalculated, but this is beyond the scope of this article and can be viewed in code: Github:https://github.com/jharwig/ppssignatureview
Using the adjacent 2 two Bezier curve points, you can calculate the vertical vector of the vector represented by this two spread value, and set its length to 1/2 of the current thickness value (Translator Note: The braces section contains 2 parts 1/2 thickness value length, it is exactly the current thickness), using Gl_triangle_ Strip the triangular sequence, it takes 2 two Bezier curve points to determine a rectangular segment containing 2 triangles.
(Translator Note: The details of the principle of the original text, it is recommended to read the code to understand the OpenGL surface subdivision, to help better understand)
This example, is the two times Bezier curve and speed control brush thickness of the method to draw out the signature, more natural.
Draw natural signatures on iOS-B