关于这个问题,我已经在另一篇blog中有所提及:

CoreText精彩文字轮廓绘制动画的一点改进

不过原有的转换代码使用Obj-C写的,在这里我们尝试将其转换为Swift语言,然后利用它实现一个测试小程序.

首先贴出原来Objc的代码:

- (void) setupTextLayer
{
    if (self.pathLayer != nil) {
        [self.penLayer removeFromSuperlayer];
        [self.pathLayer removeFromSuperlayer];
        self.pathLayer = nil;
        self.penLayer = nil;
    }

    // Create path from text
    // See: http://www.codeproject.com/KB/iPhone/Glyph.aspx
    // License: The Code Project Open License (CPOL) 1.02 http://www.codeproject.com/info/cpol10.aspx
    CGMutablePathRef letters = CGPathCreateMutable();

    CTFontRef font = CTFontCreateWithName(CFSTR("Helvetica-Bold"), 72.0f, NULL);
    NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
                           (id)font, kCTFontAttributeName,
                           nil];
    NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:@"你好,大熊猫侯佩!"
    //NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:@"hello world!"
                                                                     attributes:attrs];
    CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attrString);
    CFArrayRef runArray = CTLineGetGlyphRuns(line);

    // for each RUN
    for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runArray); runIndex++)
    {
        // Get FONT for this run
        CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, runIndex);
        CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);

        // for each GLYPH in run
        for (CFIndex runGlyphIndex = 0; runGlyphIndex < CTRunGetGlyphCount(run); runGlyphIndex++)
        {
            // get Glyph & Glyph-data
            CFRange thisGlyphRange = CFRangeMake(runGlyphIndex, 1);
            CGGlyph glyph;
            CGPoint position;
            CTRunGetGlyphs(run, thisGlyphRange, &glyph);
            CTRunGetPositions(run, thisGlyphRange, &position);

            // Get PATH of outline
            {
                CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, NULL);
                CGAffineTransform t = CGAffineTransformMakeTranslation(position.x, position.y);
                CGPathAddPath(letters, &t, letter);
                CGPathRelease(letter);
            }
        }
    }
    CFRelease(line);

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointZero];
    [path appendPath:[UIBezierPath bezierPathWithCGPath:letters]];

    CGPathRelease(letters);
    CFRelease(font);

    CAShapeLayer *pathLayer = [CAShapeLayer layer];
    pathLayer.frame = self.animationLayer.bounds;
    pathLayer.bounds = CGPathGetBoundingBox(path.CGPath);
    //pathLayer.backgroundColor = [[UIColor yellowColor] CGColor];
    pathLayer.geometryFlipped = YES;
    pathLayer.path = path.CGPath;
    pathLayer.strokeColor = [[UIColor blackColor] CGColor];
    pathLayer.fillColor = nil;
    pathLayer.lineWidth = 5.0f;
    //pathLayer.lineJoin = kCALineJoinBevel;
    pathLayer.lineJoin = kCALineJoinMiter;

    [self.animationLayer addSublayer:pathLayer];

    self.pathLayer = pathLayer;

    //happy commit
    NSLog(@"hello world!!!");

    //UIImage *penImage = [UIImage imageNamed:@"noun_project_347_2.png"];
    UIImage *penImage = [UIImage imageNamed:@"bee.png"];
    CALayer *penLayer = [CALayer layer];
    penLayer.contents = (id)penImage.CGImage;
    penLayer.anchorPoint = CGPointZero;
    penLayer.frame = CGRectMake(0.0f, 0.0f, penImage.size.width/5, penImage.size.height/5);
    [pathLayer addSublayer:penLayer];

    self.penLayer = penLayer;
}

看起来颇长啊!不过不要太在意,因为我们要用Swift重写的代码只提取其中中间的一部分,这样可以更好的重用.

新建一个项目,基于Swift语言.

在项目中新建一个Swift源代码文件,该文件扩展了String类,我们在其扩展中先写一个帮助方法的存根:

extension String{
    func toPath(font:CTFont)->CGPath{

    }
}

toPath方法用来实现任意String实例到CGPath路径的转换,在其中添加如下内容:

let letters:CGMutablePathRef = CGPathCreateMutable()
        let attrs = [kCTFontAttributeName as String:font]
        let attrString:NSAttributedString = NSAttributedString(string: self, attributes: attrs)

        let line:CTLine = CTLineCreateWithAttributedString(attrString)
        let runArray = CTLineGetGlyphRuns(line)

        for runIndex in 0..<CFArrayGetCount(runArray){
            let run = CFArrayGetValueAtIndex(runArray, runIndex)
            let runb = unsafeBitCast(run, CTRun.self)
            //let runFont:CTFont = CFDictionaryGetValue(CTRunGetAttributes(runb), kCTFontAttributeName as String) as! CTFont
            let CTFontName = unsafeBitCast(kCTFontAttributeName, UnsafePointer<Void>.self)
            let runFontC = CFDictionaryGetValue(CTRunGetAttributes(runb), CTFontName)
            let runFont = unsafeBitCast(runFontC, CTFont.self)

            //for each GLYPH in run
            for runGlyphIndex in 0..<CTRunGetGlyphCount(runb){
                //get Glyph & Glyph-data
                let glyphRange = CFRange(location: runGlyphIndex, length: 1)
                //let glyph:UnsafeMutablePointer<CGGlyph> = UnsafeMutablePointer<CGGlyph>.alloc(1)
                //glyph.initialize(0)
                var glyph:CGGlyph = 0
                let position:UnsafeMutablePointer<CGPoint> = UnsafeMutablePointer<CGPoint>.alloc(1)
                position.initialize(CGPoint.zero)
                CTRunGetGlyphs(runb, glyphRange, &glyph)
                CTRunGetPositions(runb, glyphRange, position)

                //Get PATH of outline
                //let letter = CTFontCreatePathForGlyph(runFont, glyph.memory, nil)
                let letter = CTFontCreatePathForGlyph(runFont, glyph, nil)
                var t = CGAffineTransformMakeTranslation(position.memory.x, position.memory.y)
                //let tx:UnsafeMutablePointer<CGAffineTransform> = UnsafeMutablePointer<CGAffineTransform>.alloc(1)
                //tx.initialize(t)
                CGPathAddPath(letters, &t, letter)
                //CGPathRelease(letter)
                position.destroy()
                position.dealloc(1)
            }
        }

        let path = UIBezierPath()
        path.moveToPoint(CGPoint.zero)
        path.appendPath(UIBezierPath(CGPath: letters))
        return path.CGPath

大家可以对照原来的Obj-c版本看一下,大致都是一一对应的,只有少数几个涉及操作C语言数据的地方有修改,大家可以参考我写的另一篇blog:

Swift中如何转换不同类型的Mutable指针

核心功能有了,下面就好办了!我们想要的是点击屏幕开始显示动画,于是重载如下方法:

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if isAnimating { return }

        isAnimating = true
        flyerLayer.opacity = 0.8

        pathLayer.removeAllAnimations()
        flyerLayer.removeAllAnimations()

        let strokeAnimation = CABasicAnimation(keyPath: "strokeEnd")
        strokeAnimation.duration = 20.0
        strokeAnimation.fromValue = 0.0
        strokeAnimation.toValue = 1.0
        strokeAnimation.delegate = self
        pathLayer.addAnimation(strokeAnimation, forKey: nil)

        let flyAnimation = CAKeyframeAnimation(keyPath: "position")
        flyAnimation.duration = 20.0
        flyAnimation.path = pathLayer.path
        flyAnimation.calculationMode = kCAAnimationPaced

        flyerLayer.addAnimation(flyAnimation, forKey: nil)
    }

下面是App实际运行的效果:

将String转换为其表示的路径画到屏幕上的更多相关文章

  1. C++ 将 std::string 转换为 char*

    参考: std::string to char* C++ 将 std::string 转换为 char* 目前没有直接进行转换的方法.必须通过string对象的c_str()方法,获取C-style的 ...

  2. C#中使用Buffer.BlockCopy()方法将string转换为byte array的方法:

    public static void BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count); 将指定数目的字 ...

  3. C++不存在从std::string转换为LPCWSTR的适当函数

    LPCWSTR是什么类型呢? 看看如何定义的: typedef const wchar_t* LPCWSTR; 顾名思义就是: LPCWSTR是一个指向unicode编码字符串的32位指针,所指向字符 ...

  4. string[]转换为int[]

    今天碰到一个问题,要把string[]转换为int[],但是又不想使用循环转换,找了好久最后找到了这种方法,特此记录下. string[] input = { "1", " ...

  5. c#中char、string转换为十六进制byte的浅析

    问题引出: string转换为byte(十六进制) static void Main(string[] args) { "; byte[] b = Encoding.Default.GetB ...

  6. JAVA 利用SimpleDateFormat将String转换为格式化的日期

    1. /** * 使用用户格式提取字符串日期 * * @param strDate 日期字符串 * @param pattern 日期格式 * @return */ public static Dat ...

  7. 【VS开发】ConvertBSTRToString(filename) 不能将string转换为BSTR

    环境:win7,x64,vs2008 sp1 把VC 6.0的工程文件用VS2008打开,编译报错: error C2664:"_com_util::ConvertBSTRToString& ...

  8. (转)第04节:Fabric.js用路径画不规则图形

    在Canvas上画方形.圆形.三角形都是很容易的,只要调用fabric对应的方法就可以了,但这些都是规则的图形,如果你想画一个不规则的图形,这时候你可以用fabric.js提供的路径绘图方法.所谓路径 ...

  9. 有趣html5(两)----使用canvas结合剧本画在画布上的简单图(html5另一个强大)

    请珍惜劳动小编成果,这篇文章是原来小编,转载请注明出处. 于html5中能够使用canvas标签在画布上绘图,先直接上代码,这篇文章先简介一下canvas的用法.简单画几个圆,矩形,三角形,写字. 在 ...

随机推荐

  1. [HAOI 2009]逆序对数列

    Description 对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成的 数列,可以很容易求出有多少个逆序对数.那么逆 ...

  2. BZOJ 4372 烁烁的游戏

    Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮 ...

  3. Set 集合

    [题目描述]现在给你一些连续的整数,它们是从 A 到 B 的整数.一开始每个整数都属于各自的集合,然后你需要进行如下操作:每次选择两个属于不同集合的整数,如果这两个整数拥有大于等于 P 的公共质因数, ...

  4. HDU2108和HDU2036(叉乘)

    hdu2108 判断是否为凸边形 判断连续三点的叉乘 若为凸,内角<180:若为凹,内角>180 所以通过正负来判断 #include <iostream> #include ...

  5. 2015 多校联赛 ——HDU5348(搜索)

    Problem Description As we all kown, MZL hates the endless loop deeply, and he commands you to solve ...

  6. Mysql 基于GTID的主从复制(实操)

    实现环境: Master 主:192.168.0.102 (Mysql 5.6.36) Slave  从 :192.168.0.103 (Mysql 5.6.36) 步骤1.在主DB服务器上建立复制账 ...

  7. 修改Linux命令提示符

    vim .bashrc export PS1='\e[1;32m\u\e[m\e[1;33m@\e[m\e[1;35m\h\e[m:\W\$'

  8. Python【第三课】 函数基础

    本篇内容 函数基本语法及特性 嵌套函数 递归函数 匿名函数 高阶函数 内置函数 1.函数的基本语法及特性 1.1 函数概念 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提 ...

  9. HL7工具安装步骤

    下载目录:http://gforge.hl7.org/gf/ 说明:在安装HL7V3学习工具之前,确保本机已安装IIS服务和Access数据库. 各种软件见附件. 1.下载安装步骤   RIM模型下载 ...

  10. 好久没用IJ写Java 之 《求输入的一个数中包含奇数、偶数、零的个数》

    /** *Created by xuzili at 22:12 on 2018/4/4 */ // 以上注释使用了IntelliJ Idea的File-Settings-Editor-Live Tem ...