如何在iOS设备上捕捉用户签名

移动开发 iOS
Square Engineering Blog 上有一篇很棒的文章,为 Android 带来了更流畅的签名,但我没有找到任何与 iOS 相关的介绍。所以,在 iOS 设备上捕捉用户签名的最好方式是什么呢?

Square Engineering Blog 上有一篇很棒的文章,为 Android 带来了更流畅的签名,但我没有找到任何与 iOS 相关的介绍。所以,在 iOS 设备上捕捉用户签名的***方式是什么呢?

虽然我没有找到关于签名捕捉的文章,但 App Store 上已有一些应用很好地实现了签名捕捉。我的目标用户体验是达到 iPad 应用 Paper by 53 那样的效果(它是一个绘图应用,有着漂亮且***响应性的笔刷)。

本文所有的代码都可以在 Github 仓库 SignatureDemo 里找到。

点点相连

rgegfhrthr652d6469616772616d2d6c696e65732e706e67

最简单的方式是捕捉用户的触摸点并用直线将它们连接在一起。

在 UIView 子类的初始化方法中,创建一个 path ,以及用于捕捉触摸事件的手势识别器。

  1. // 创建一个 path 以连接各点 
  2. path = [UIBezierPath bezierPath]; 
  3.   
  4. // 捕捉触摸 
  5. UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; 
  6. pan.maximumNumberOfTouches = pan.minimumNumberOfTouches = 1; 
  7. [self addGestureRecognizer:pan]; 

捕捉 pan 手势的触摸点,并通过连线将其放入 bézier path 里:

  1. - (void)pan:(UIPanGestureRecognizer *)pan { 
  2.     CGPoint currentPoint = [pan locationInView:self]; 
  3.   
  4.     if (pan.state == UIGestureRecognizerStateBegan) { 
  5.         [path moveToPoint:currentPoint]; 
  6.     } else if (pan.state == UIGestureRecognizerStateChanged) 
  7.         [path addLineToPoint:currentPoint]; 
  8.   
  9.     [self setNeedsDisplay]; 

画出 path:

  1. - (void)drawRect:(CGRect)rect 
  2.     [[UIColor blackColor] setStroke]; 
  3.     [path stroke]; 

sdvgrhgrthrth2d6c65747465722d6a2e706e67

上图是用这种技术画出的字母 “J” ,它也揭示了一些问题:在较慢的速度下, iOS 可以捕捉到足够多的触摸点,因此看起来较平滑,但稍快的移动就会导致触摸点之间较大的间距,签名看起来就是一些直线段相连。

2012 年的 Apple 开发者大会有一个 session 叫做 创建高级手势识别器,它用了一点数学来解决此问题。

二次贝塞尔曲线

trhrehrthrtr616472617469632e706e67

作为用线段连接各触摸点的代替,我们改用二次贝塞尔曲线来连接这些点,使用前述的 WWDC session 上讨论的技术(定位到 42 分 15 秒)。用二次贝塞尔曲线来连接触摸点,使用触摸点作为控制点以及中间点作为起点和终点。

添加二次曲线到之前的代码里要求存储前一个触摸点,所以要添加一个实例变量:

  1. CGPoint previousPoint; 

并创建一个函数来计算两点的中间点:

  1. static CGPoint midpoint(CGPoint p0, CGPoint p1) { 
  2.     return (CGPoint) { 
  3.         (p0.x + p1.x) / 2.0, 
  4.         (p0.y + p1.y) / 2.0 
  5.     }; 

再更新 pan 手势处理器,用二次曲线替换直线:

  1. - (void)pan:(UIPanGestureRecognizer *)pan { 
  2.     CGPoint currentPoint = [pan locationInView:self]; 
  3.     CGPoint midPoint = midpoint(previousPoint, currentPoint); 
  4.   
  5.     if (pan.state == UIGestureRecognizerStateBegan) { 
  6.         [path moveToPoint:currentPoint]; 
  7.     } else if (pan.state == UIGestureRecognizerStateChanged) { 
  8.         [path addQuadCurveToPoint:midPoint controlPoint:previousPoint]; 
  9.     } 
  10.   
  11.     previousPoint = currentPoint; 
  12.   
  13.     [self setNeedsDisplay]; 
  14.  
  15. grefbd6a2d7175616472617469632e706e67 

grefbd6a2d7175616472617469632e706e67

并没有改写太多代码,但我们已经看到了巨大的不同。触摸点不再可见,但对于捕捉签名来说,它依然有些乏味。每个曲线都是同样的宽度,这不符合实际用钢笔签名的感觉。

可变的线宽

基于触摸速度,宽度可变,这样就能创建出更加自然的笔画。 UIPanGestureRecognizer 已经包含有一个叫做 velocityInView: 的方法,它用一个 CGPoint 返回当前触摸的速度。

为了渲染出一个可变宽度的笔画,我切换到 OpenGL ES 和一个能转换笔画为三角形(具体说来,是三角带(triangle strip))的叫做镶嵌(tesselation)的技术(OpenGL 支持画线,但 iOS 不支持平滑过渡的可变宽度)。沿曲线的二次分点同样需要被计算,但这超出了本文讨论的范畴。还请看看 Github 上的源代码了解细节吧。

给定两个点,计算出一个垂直的向量,它的大小设置为当前厚度的一半。基于 GL_TRIANGLE_STRIP 的自然特性,只需要两个点就能用两个三角形去创建下一个矩形。

sdfvs676c652d73747269702e706e67

下面是使用二次贝塞尔曲线,并根据速度调节笔画粗细而创造出的一个具有视觉吸引力且非常自然的签名。

regrer6f70656e676c2e706e67

原文出处: JASON HARWIG   

译文出处: nixzhu(@nixzhu)

责任编辑:闫佳明 来源: github
相关推荐

2022-09-13 08:40:24

AndroidLinux

2016-08-16 08:26:19

Linuxsignalsigaction

2018-07-20 14:20:24

Linux用户组管理员

2012-04-16 17:15:12

iOS 5定制用户界面

2018-05-10 15:05:41

Linux用户日期命令

2022-11-01 15:49:52

2018-11-26 08:45:29

Linux驱动程序命令

2021-09-27 07:57:15

MEAT安全工具安全取证

2021-06-02 09:36:49

物联网恶意软件IoT

2019-02-28 09:30:04

Ubuntusudo命令

2017-01-11 16:41:16

Linux设备文件文件系统

2011-01-19 11:17:20

2021-08-27 11:03:57

Azure公有云云原生

2021-01-18 08:00:00

Linux虚拟机磁盘

2013-06-27 10:57:45

判断当前iOS设备iOS开发移动开发

2020-03-23 17:58:29

LinuxSSH

2017-02-14 10:12:44

2011-08-02 10:55:05

Oracle 10glvm映射裸设备

2019-08-02 15:30:42

UbuntuMongoDB命令

2019-01-07 09:50:06

Linuxtarball命令
点赞
收藏

51CTO技术栈公众号