当前位置: > > > Swift - 捕获用户签名(用户在屏幕上手写签名,并生成图片)

Swift - 捕获用户签名(用户在屏幕上手写签名,并生成图片)

(本文代码已升级至Swift3)

本文介绍如何使用Swift语言,在iOS设备上捕捉用户的签名(其实这个本质就是一个简单的画图板程序)。

实现功能如下:
1,页面上方提供一个签名区域(UIView),用户可以在这个区域手写签字。
2,点击“预览签名”,会获取用户签名生成UIImage,在下方的imageView中显示。
3,点击“保存签名”,会将用户签名保存到设备相册中。

效果图如下: 
         

代码如下:
--- DrawSignatureView.swift (签名视图组件) ---
import UIKit

open class DrawSignatureView: UIView {
    
    // 公共属性
    open var lineWidth: CGFloat = 2.0 {
        didSet {
            self.path.lineWidth = lineWidth
        }
    }
    open var strokeColor: UIColor = UIColor.black
    open var signatureBackgroundColor: UIColor = UIColor.white
    
    // 私有属性
    fileprivate var path = UIBezierPath()
    fileprivate var pts = [CGPoint](repeating: CGPoint(), count: 5)
    fileprivate var ctr = 0
    
    // Init
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.backgroundColor = self.signatureBackgroundColor
        self.path.lineWidth = self.lineWidth
    }
    
    // Init
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        self.backgroundColor = self.signatureBackgroundColor
        self.path.lineWidth = self.lineWidth
    }
    
    // Draw
    override open func draw(_ rect: CGRect) {
        self.strokeColor.setStroke()
        self.path.stroke()
    }
    
    // 触摸签名相关方法
    override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let firstTouch = touches.first{
            let touchPoint = firstTouch.location(in: self)
            self.ctr = 0
            self.pts[0] = touchPoint
        }
    }
    
    override open func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let firstTouch = touches.first{
            let touchPoint = firstTouch.location(in: self)
            self.ctr += 1
            self.pts[self.ctr] = touchPoint
            if (self.ctr == 4) {
                self.pts[3] = CGPoint(x: (self.pts[2].x + self.pts[4].x)/2.0,
                    y: (self.pts[2].y + self.pts[4].y)/2.0)
                self.path.move(to: self.pts[0])
                self.path.addCurve(to: self.pts[3], controlPoint1:self.pts[1],
                    controlPoint2:self.pts[2])
                
                self.setNeedsDisplay()
                self.pts[0] = self.pts[3]
                self.pts[1] = self.pts[4]
                self.ctr = 1
            }
            
            self.setNeedsDisplay()
        }
    }
    
    override open func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        if self.ctr == 0{
            let touchPoint = self.pts[0]
            self.path.move(to: CGPoint(x: touchPoint.x-1.0,y: touchPoint.y))
            self.path.addLine(to: CGPoint(x: touchPoint.x+1.0,y: touchPoint.y))
            self.setNeedsDisplay()
        } else {
            self.ctr = 0
        }
    }
    
    // 签名视图清空
    open func clearSignature() {
        self.path.removeAllPoints()
        self.setNeedsDisplay()
    }
    
    // 将签名保存为UIImage
    open func getSignature() ->UIImage {
        UIGraphicsBeginImageContext(CGSize(width: self.bounds.size.width,
            height: self.bounds.size.height))
        self.layer.render(in: UIGraphicsGetCurrentContext()!)
        let signature: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return signature
    }
}



--- ViewController.swift (使用样例) ---
import UIKit

class ViewController: UIViewController {
    
    //签名预览
    @IBOutlet weak var imageView: UIImageView!
    
    //签名区域视图
    var drawView:DrawSignatureView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //签名区域位置尺寸
        var drawViewFrame = self.view.bounds
        drawViewFrame.size.height = 200
        //添加签名区域
        drawView = DrawSignatureView(frame: drawViewFrame)
        self.view.addSubview(drawView)
             
    }

    //预览签名
    @IBAction func previewSignature(_ sender: AnyObject) {
        let signatureImage = self.drawView.getSignature()
        imageView.image = signatureImage
    }
    
    //保存签名
    @IBAction func savaSignature(_ sender: AnyObject) {
        let signatureImage = self.drawView.getSignature()
        UIImageWriteToSavedPhotosAlbum(signatureImage, nil, nil, nil)
        self.drawView.clearSignature()
    }
    
    //清除签名
    @IBAction func clearSignature(_ sender: AnyObject) {
        
        
        self.drawView.clearSignature()
        self.imageView.image = nil
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
源码下载:hangge_1013.zip
评论10
  • 10楼
    2017-01-19 08:31
    swift小白纸

    hangge 有工程么 我可以下载一下么

    站长回复

    有啊,文章末尾就有下载链接。

  • 9楼
    2016-06-20 10:54
    swift小白痴

    hangge,DrawSignatureView.swift里面19-33行,两个Init是干嘛用的?能不能解释一下90-96行签名保存UIImage,以及3个触摸签名相关方法,不是能看得很懂,谢谢了

    站长回复

    继承UIView实现自定义组件的话,这两个Init方法都要写的,作用都是初始化数据。 将签名转成UIImage这个就是通过绘图上下文实现,就是文中那几句代码。 触摸方法里面做的事就是不断地记录坐标点让后绘制曲线。

  • 8楼
    2016-06-20 10:48
    swift小白痴

    hangge,DrawSignatureView.swift里面第38行self.path.stroke()是什么意思?

    站长回复

    就是根据这个路径画线。

  • 7楼
    2016-06-20 10:06
    swift小白痴

    hangge,DrawSignatureView.swift里面,16,17行私有属性,pts,ctr定义的是什么?private var pts = [CGPoint](count: 5, repeatedValue: CGPoint()) 这句话是什么意思?

    站长回复

    pts里是存储绘制时最新的5个点坐标,ctr是索引,每当手指移动的时候就会记录一个点。每有5个点的话则绘制一段曲线,依次循环。整个签名图就是由一段段曲线组成的。

  • 6楼
    2016-06-20 09:44
    swift 小白痴

    hangge,DrawSignatureView.swift 中,第7行 didSet{}是干嘛用的?

    站长回复

    didSet的用法可以参考我原来写的这篇文章:Swift - 属性观察者(willSet与didSet)

  • 5楼
    2016-06-20 09:31
    swift小白痴

    hangge,在ViewController.swift中,第9行,18行,19行,是什么意思

    站长回复

    将自定义的签名组件添加到页面视图上。

  • 4楼
    2016-06-20 09:23
    swift小白痴

    hangge,在ViewController.swift中,第33行,38行,self.drawView.clearSignature()是用来做什么的

    站长回复

    将上方签名区域(DrawSignatureView)中绘制的内容清除。

  • 3楼
    2016-04-12 19:51
    hangge999

    嗯,好的谢谢hangge。

    站长回复

    不客气:)

  • 2楼
    2016-04-08 18:40
    hangge999

    嗯,好的,谢谢hangge。我会关注的,不过我要怎么搜到这个文章呢= =。那下周再问问您吧。或者麻烦您发邮件通知一下我= =

    站长回复

    关注最新文章就可以了,大概周三、周四的时候会发。

  • 1楼
    2016-04-05 18:51
    hangge999

    hangge怎么获取UIImageWriteToSavedPhotosAlbum保存在相册的地址呢,就是我保存在了相册里,并且我要取出它的地址

    站长回复

    UIImageWriteToSavedPhotosAlbum保存后不会返回地址,如果你需要得到路径的话可以换一种方式实现。我下周写篇相关文章,你可以关注下。