将String转换为其表示的路径画到屏幕上
关于这个问题,我已经在另一篇blog中有所提及:
不过原有的转换代码使用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:
核心功能有了,下面就好办了!我们想要的是点击屏幕开始显示动画,于是重载如下方法:
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转换为其表示的路径画到屏幕上的更多相关文章
- C++ 将 std::string 转换为 char*
参考: std::string to char* C++ 将 std::string 转换为 char* 目前没有直接进行转换的方法.必须通过string对象的c_str()方法,获取C-style的 ...
- C#中使用Buffer.BlockCopy()方法将string转换为byte array的方法:
public static void BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count); 将指定数目的字 ...
- C++不存在从std::string转换为LPCWSTR的适当函数
LPCWSTR是什么类型呢? 看看如何定义的: typedef const wchar_t* LPCWSTR; 顾名思义就是: LPCWSTR是一个指向unicode编码字符串的32位指针,所指向字符 ...
- string[]转换为int[]
今天碰到一个问题,要把string[]转换为int[],但是又不想使用循环转换,找了好久最后找到了这种方法,特此记录下. string[] input = { "1", " ...
- c#中char、string转换为十六进制byte的浅析
问题引出: string转换为byte(十六进制) static void Main(string[] args) { "; byte[] b = Encoding.Default.GetB ...
- JAVA 利用SimpleDateFormat将String转换为格式化的日期
1. /** * 使用用户格式提取字符串日期 * * @param strDate 日期字符串 * @param pattern 日期格式 * @return */ public static Dat ...
- 【VS开发】ConvertBSTRToString(filename) 不能将string转换为BSTR
环境:win7,x64,vs2008 sp1 把VC 6.0的工程文件用VS2008打开,编译报错: error C2664:"_com_util::ConvertBSTRToString& ...
- (转)第04节:Fabric.js用路径画不规则图形
在Canvas上画方形.圆形.三角形都是很容易的,只要调用fabric对应的方法就可以了,但这些都是规则的图形,如果你想画一个不规则的图形,这时候你可以用fabric.js提供的路径绘图方法.所谓路径 ...
- 有趣html5(两)----使用canvas结合剧本画在画布上的简单图(html5另一个强大)
请珍惜劳动小编成果,这篇文章是原来小编,转载请注明出处. 于html5中能够使用canvas标签在画布上绘图,先直接上代码,这篇文章先简介一下canvas的用法.简单画几个圆,矩形,三角形,写字. 在 ...
随机推荐
- pat 1001 A+B Format
题目链接:传送门 题目简述: 1. 给定两个整数值a,b: 2.范围-1000000 <= a, b <= 1000000: 3.按指定格式输出结果 例:-100000 9 输出: -99 ...
- [测试题]数组(array)
Description Input Output Sample Input1 3 2 75 4 2 Sample Output1 999999732 Sample Explanation1 Sampl ...
- [PA 2014]Pakowanie
Description 你有n个物品和m个包.物品有重量,且不可被分割:包也有各自的容量.要把所有物品装入包中,至少需要几个包? Input 第一行两个整数n,m(1<=n<=24,1&l ...
- [bzoj4151][AMPPZ2014]The Cave
来自FallDream的博客,未经允许,请勿转载,谢谢. 给定一棵有n个节点的树,相邻两点之间的距离为1. 请找到一个点x,使其满足所有m条限制,其中第i条限制为dist(x,a[i])+dist(x ...
- [bzoj4822][Cqoi2017]老C的任务&[bzoj1935][Shoi2007]Tree 园丁的烦恼
来自FallDream的博客,未经允许,请勿转载,谢谢. 老 C 是个程序员. 最近老 C 从老板那里接到了一个任务——给城市中的手机基站写个管理系统.作为经验丰富的程序员,老 C 轻松地完成 ...
- 【完整项目】使用Scrapy模拟HTTP POST,获取完美名字
1. 背景 最近有人委托我给小孩起个名字,说名字最好符合周易五行生克理论,然后给了我个网址,说像是这个网站中的八字测名,输入名字和生辰八字等信息,会给出来这个名字的分数和对未来人生的预测.当父母的自然 ...
- JPA注解实体类,给表添加创建时间,更新时间,id的生成以及创建唯一约束
首先创建一个BaseModel,自动生成创建时间和更新时间 @SuppressWarnings("serial") @MappedSuperclass public class B ...
- 笔记7 AOP练习<有疑问>
场景描述: 核心业务:举行一场古典音乐会. 周边功能:观众入场,关闭手机.落座,觉得音乐好听时鼓掌,觉都不好听则退票.(切面) 1.编写切点(切点用于准确定位应该在什么地方应用切面的通 知)----即 ...
- C语言程序设计第一次实验
一. 1.输入圆的半径,计算圆的面积周长问题 2流程图 3测试数据及运算结果 4实验分析 不会输入r,后来问了同学得到解决. 二. 1.输入一个四位年份,判断其是否是闰年.闰年的判别条件是概念年份能被 ...
- react 踩的坑
1.如上图所示:没有任何语法错误,可是只要加上</button>闭合标签后就乱套了 解决方案:sublimetext view-syntax-babel-javascript(babel) ...