CAShapeLayer文字动画

文字动画也是CAShapeLayer图形动画的一种,巧妙运用文字动画可以实现很不错的效果,比如半糖app的下拉动画。本文就主要讲一下其实现原理。

文字动画主要分为两部分:

  • 将文字转化为CAShapeLayer
  • 通过更改CAShapeLayer的StrokeEnd属性值生成动画

将文字转换为CAShapeLayer

将文字转换为CAShapeLayer的过程比较复杂,可以细分为以下几个步骤:

  • 创建NSAttributedString并生成CTLineRef
  • 使用CTLineRef生成CTRunRef数组
  • 遍历CTRunRef数组,得到每个CTRunRef
  • 遍历CTRunRef中每个长度为1的区间生成CGGlyph并转换为CGPath路径,将所有路径拼接起来
  • 创建ShapeLayer并将生成的路径赋值给该ShapeLayer

以下是每个步骤的实现方式:

创建NSAttributedString并生成CTLineRef

// 定义字体属性
CTFontRef font = CTFontCreateWithName(CFSTR("HelveticaNeue-UltraLight"), fontSize, NULL);
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)font, kCTFontAttributeName,nil];
// 创建NSAttributedString
NSAttributedString *str = [[NSAttributedString alloc] initWithString:text attributes:attrs];
CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)str);

使用CTLineRef生成CTRunRef数组

CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)str);
CFArrayRef runArray = CTLineGetGlyphRuns(line);

遍历CTRunRef数组,得到每个CTRunRef

for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runArray); runIndex++) {
    // 
    CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, runIndex);
    CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);
}

遍历CTRunRef中每个长度为1的区间生成CGGlyph并转换为CGPath路径,将所有路径拼接起来

for (CFIndex glyphIndex = 0; glyphIndex < CTRunGetGlyphCount(run); glyphIndex++) {
      
    CGGlyph glyph;
    CGPoint position;
    CFRange currentRange = CFRangeMake(glyphIndex, 1);
    CTRunGetGlyphs(run, currentRange, &glyph);
    CTRunGetPositions(run, currentRange, &position);
            
    CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, NULL);
    CGAffineTransform t = CGAffineTransformMakeTranslation(position.x, position.y);
    CGPathAddPath(letters, &t, letter);
    CGPathRelease(letter);
}

创建ShapeLayer并将生成的路径赋值给该ShapeLayer

// 创建UIBezierPath
UIBezierPath *path = [UIBezierPath bezierPathWithCGPath:letters];
// 创建并配置CAShapeLayer
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.frame = self.bounds;
pathLayer.bounds = CGPathGetBoundingBox(path.CGPath);
pathLayer.geometryFlipped = YES;
pathLayer.path = path.CGPath;
pathLayer.strokeColor = fontColor.CGColor;
pathLayer.fillColor = nil;
pathLayer.lineWidth = 1.0f;
pathLayer.lineJoin = kCALineJoinBevel;
pathLayer.strokeStart = 0;
pathLayer.strokeEnd = 0;

最后,将ShapeLayer添加到动画图层中就行了

生成文字动画

通过改变ShapeLayer的StrokeEnd属性值就可以生成文字动画

添加Slider

- (void)setupSlider {
    CGFloat leftMargin = 20;
    UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(leftMargin, kMainHeight - 30, kMainWidth - leftMargin * 2, 3)];
    slider.minimumValue = 0;
    slider.maximumValue = 1;
    [self.view addSubview:slider];
    [slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
}

实现Slider的ValueChange方法

- (void)sliderValueChanged:(UISlider *)sender {
    self.pathLayer.strokeEnd = sender.value;
}

至此,一个文字动画就完成了

本文demo的github地址:<a>https://github.com/zephyrw/TextAnimationDemo.git</a>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 一、CAShapelayer 我们知道可以不使用图片情况下利用CGpath去构建任意形状的阴影。其实我们也可...
    小猫仔阅读 1,413评论 0 5
  • 动画:CAAnimation使用 使用动画来写名字! 技术点 { // 先导进#import 头文件 使用CASh...
    Evan叶少阅读 925评论 0 4
  • 架构使用的语言知识 这几年数据分析 迅速发展,我们也做了一个微数据分析工具。该产品已成功运行三年,满足日活百万的企...
    CobubRazor阅读 1,596评论 1 2
  • 自己一直都是喜欢操场的,愿意一圈一圈绕着走,好像永远都不知疲倦的样子。 有好友同行自如聊天很惬意,更加理解朋友的想...
    缄默9阅读 302评论 2 1