[swift]读取svg图片为UIBezierPath,开心做动画

前端之家收集整理的这篇文章主要介绍了[swift]读取svg图片为UIBezierPath,开心做动画前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

https://segmentfault.com/a/1190000002580541


更新

给对本文感兴趣的朋友们推荐个好东西:paintcode

动画预览

先扯淡

最近手痒又想整点动画玩玩,但是想了几个主意发现稍微复杂一点的手写都一定会累爆。这篇文章记录一下今天折腾的一个方案。说来简单,就是用矢量设计工具舒舒服服的做好设计,然后输出svg格式,再用NSXMLParser去读出来,转换成UIBezierPath,然后就天高任鸟飞~

清晰起见,这里不使用各种库,由上面的二维码动画为例,只转换最简单的矩形。需要更多高能操作的,出门右转SVGKit

开工

筹备材料先,首先找个能提供svg格式下载的二维码生成网站,比如这个。拿到svg文件后用文本编辑器打开可以看到其实是一个描述矢量图形的xml,而且里面几百个矩形。。。如果你用的生成网站跟我一样,还会有一个白色的背景矩形,待会儿我们会把它排除掉。

准备工作就到这了,接下来我们会用NSXMLParser来解析这个二维码

新建一个Single View Application,把二维码拖进项目里去,在ViewController添加一个UIView作为二维码的容器:

class ViewController: UIViewController {

    let qrView = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        qrView.center = view.center
        view.addSubview(qrView)
    }
    
    ...
}

初始化一个NSXMLParser去解析svg,同时让ViewController实现NSXMLParserDelegate`
parser(_:didStartElement:namespaceURI:qualifiedName:attributes:)
parserDidEndDocument(_:)`两个方法用于处理解析结果:

UIViewController,NSXMLParserDelegate {
    
    ...
    
    override func viewDidLoad() {
        ...
        
        let qrPath = NSBundle.mainBundle().pathForResource("zcfan_qrcode",ofType: "svg")!
        let qrData = NSData(contentsOfFile: qrPath)
        let xmlParser = NSXMLParser(data: qrData)
        xmlParser.delegate = self
        xmlParser.parse()
    }
    
    func parser(parser: NSXMLParser!,didStartElement elementName: String!,namespaceURI: String!,qualifiedName qName: String!,attributes attributeDict: [NSObject : AnyObject]!) {
        // 每当解析到一个新标签,这里就会被调用
    }
    
    func parserDidEndDocument(parser: NSXMLParser!) {
        // 整个 svg 文件解析完毕后,这里就会被调用
    }
    
    ...
}

接下来我们会在parser(_:didStartElement:namespaceURI:qualifiedName:attributes:)中把遇到的每一个形如:

<rect... x="0"y="0"width="12"height=fill="black"/>

标签转换成CGRect保存在数组中,并在parserDidEndDocument(_:)中把他们转换为CAShapeLayer添加动画。

先来看看parser(_:didStartElement:namespaceURI:qualifiedName:attributes:)内容

...

var rects = [CGRect]()  // 用于存储二维码

func // 只转换 “黑色” 的二维码 “方块”
    if elementName == "rect" && (attributeDict["fill"] as String) == "black" {
        let x = (attributeDict["x"] as NSString).doubleValue
        let y = (attributeDict["y"] as NSString).doubleValue
        let w = (attributeDict["width"] as NSString).doubleValue
        let h = (attributeDict["height"] as NSString).doubleValue
        
        let rect = CGRect(x: x,y: y,width: w,height: h)
        rects.append(rect)
        
    // 设置 qrView 的尺寸为 svg 图像的大小
    } else if elementName == "svg" {
        let w = (attributeDict[NSString).doubleValue
        
        qrView.bounds = CGRect(x: 0,y:  接下来是parserDidEndDocument(_:),在这里我们要把二维码显示出来:

...

func parserDidEndDocument(parser: NSXMLParser!) {
    for r in rects {
        let rectLayer = CAShapeLayer()
        
        rectLayer.fillColor = UIColor.darkGrayColor().CGColor
        rectLayer.strokeColor = nil
        rectLayer.path = UIBezierPath(rect: CGRect(origin: CGPointZero,size: r.size)).CGPath  // #1
        rectLayer.frame = r  // #2
        
        qrView.layer.addSublayer(rectLayer)
    }
}

...

#1#2:看着有点晕?代码不直观的话不妨稍微把玩一下,原因很简单,但要用语言解释我的舌头可能会打结。。。

至此,运行项目应该就能在屏幕上看到一个大二维码了!

加特技! Duang~

回到上面的parserDidEndDocument(_:)方法,然后把它改到面目全非!Duang~

func parserDidEndDocument(parser: NSXMLParser!) {
    
    qrView.layer.shadowColor = UIColor.grayColor().CGColor
    qrView.layer.shadowRadius = 4
    qrView.layer.shadowOpacity = 1
    qrView.layer.shadowOffset = CGSizeZero
    
    for r in rects {
        let rectLayer = CAShapeLayer()
        
        rectLayer.fillColor = UIColor.darkGrayColor().CGColor
        rectLayer.strokeColor = nil
        rectLayer.path = UIBezierPath(rect: CGRect(origin: CGPointZero,size: r.size)).CGPath
        rectLayer.frame = r
        
        var startTransform = CATransform3DIdentity
        startTransform.m34 = 1.0 / -20  // 透视
        startTransform = CATransform3DRotate(startTransform,CGFloat(M_PI)*0.5,1,128)">0)  // 沿 y 轴旋转 π/2 圈,待会再动画转回来
        
        // transform 动画
        let transAnim = CABasicAnimation(keyPath: "transform")
        transAnim.duration = drand48() * 4  // 随机一个持续时间
        transAnim.fromValue = NSValue(CATransform3D: startTransform)
        transAnim.toValue = CATransform3D: CATransform3DIdentity)
        rectLayer.addAnimation(transAnim,forKey: "transAnim")
        
        // 透明度动画
        let alphaAnim = "opacity")
        alphaAnim.duration = transAnim.duration
        alphaAnim.fromValue = 0
        alphaAnim.toValue = 1
        rectLayer.addAnimation(alphaAnim,68)">"alphaAnim")
        
        qrView.layer.addSublayer(rectLayer)
    }
}

完工

没眼看,不录gif了。。。心塞。。。

继续加特技

手贱没忍住。。。二维码真是玩不坏。。。

猜你在找的Swift相关文章