原文地址: Animating text layers using CoreAnimation and CoreText frameworks in iOS SDK
4月13號 使用iOS SDK中的CoreAnimation和CoreText實現(xiàn)文本層動畫
CoreAnimation
是一個非常強大的框架阔加。通過使用CABasicAnimation
,CAKeyFrameAnimation
或者CAAnimationGroup
背犯,我們可以創(chuàng)建驚艷的用戶體驗來王滤,同時基本上是沒有什么限制的幔托。僅僅取決于我們想要在屏幕上展示什么和它是怎么交互的。事實證明缔逛,CoreAnimation
也可以和一些其他的框架(如CoreGraphics
或者CoreText
)組合使用,這也給了開發(fā)者創(chuàng)造更加驚艷的動畫的能力尼桶。使用CoreText
和CoreAnimation
我們可以給任何指定字體類型和字體大小的文本添加動畫。在這篇文章中我會展示一種方式如何做到這樣锯仪。
CoreText基礎(chǔ)
首先泵督,讓我向大家展示一下CoreText
的基礎(chǔ)。為了給文本添加動畫庶喜,我們必須知道線條(line
)和象形符號(glyph
)是什么小腊,這會幫助我們理解從一個文本生成一條路徑(path)的整個過程。蘋果已經(jīng)為我們奠定了CoreText
的基礎(chǔ)知識溃卡。所有的這些都可以在下面看到溢豆。下面是我收集的最重要的信息。
在此層次結(jié)構(gòu)的頂部是frame setter
對象瘸羡。帶有屬性的字符串和圖形路徑作為輸入。一個frame setter
生成文本的一個或者多個frame
搓茬。每一個frame對象都代表一個段落犹赖。要生成frame
,frame setter
調(diào)用一個typesetter
對象卷仑。當一個frame setter
奠定一個特定的frame
的時候峻村,它適用于段落樣式,包括對齊方式锡凝,制表位粘昨,或者行距等屬性。typesetter將這些帶有屬性的字符串中的字符轉(zhuǎn)換成象形字符(glyphs)窜锯,同時也適合那些象形字符(glyphs
)形成填充文字框的線條张肾。
每一個frame
對象包含段落的線對象,它代表一個段落中文本的一行锚扎。一個frame對象可能只包含一個單一的長line對象吞瞪,也可能包含一系列的line。line對象在frame設(shè)置時期被typesetter創(chuàng)建驾孔。每一個line對象包含一組象形字符運行(glyph run
)對象芍秆。一個象形字符運行(glyph run
)是一組共享相同屬性和方向的連續(xù)象形字符(glyph
)惯疙。typesetter
創(chuàng)建象形字符運行(glyph run
)就像它從字符串、屬性和字體對象生產(chǎn)line一樣妖啥。這意味著霉颠,一個line構(gòu)成一個或者多個象形字符運行(glyph run
)。在層次結(jié)構(gòu)的尾部是通常代表單個文本字符的象形字符(glyph
)對象荆虱。經(jīng)過我們對CoreText
的基本熟悉蒿偎,我們現(xiàn)在可以文本層動畫了。
Animating text layer
為了給文本層添加動畫克伊,我們需要將其轉(zhuǎn)換成CGPath
對象酥郭。首先我們必須創(chuàng)建我們想要添加動畫的帶屬性的字符,然后我們?yōu)榱说玫较笮巫址\行(glyph run
)不得不從這個字符串中創(chuàng)建一個line
對象愿吹。下面的代碼展示了我們?nèi)绾螌崿F(xiàn)這些目的:
let attrString = NSAttributedString(string: text, attributes: [kCTFontAttributeName as String : font])
let line = CTLineCreateWithAttributedString(attrString)
let runArray = CTLineGetGlyphRuns(line)
這里我們將所有的象形字符運行(glyph run
)保存在runArray
中不从。我們通過這個數(shù)組循環(huán),并且從每一個象形字符運行(glyph run
)來看犁跪,我們可以得到這些字體椿息,以及所有相應(yīng)的象形字符(glyph
)。現(xiàn)在我們可以通過遍歷所有的象形字符(glyph
)來選出特定的象形字符(glyph
)對象坷衍。當我們有了這個對象寝优,我們可以計算它的位置,并使用CTFontCreatePathForGlyph
函數(shù)將其轉(zhuǎn)換成path
對象枫耳。通過擁有一個路徑就知道它的位置乏矾,我們就可以創(chuàng)建一個有象形字符(glyph
)路徑組合而成的總體路徑。下面的偽代碼顯示了整體算法:
%For each glyph run
for runIndex in 0..<CFArrayGetCount(runArray) {
let runFont = %Get a font from a single glyph
%For each glyph in a single glyph run
for runGlyphIndex in 0..<CTRunGetGlyphCount(run) {
var glyph = %Get a glyph
var position = %Get glyph’s position
%Get a letter path from a single glyph
let letter = CTFontCreatePathForGlyph(runFont, glyph, nil)
%Make a translation to a desired position
var t = CGAffineTransformMakeTranslation(position.x, position.y)
%Add a single letter path to the whole path
CGPathAddPath(letters, &t, letter)
}
}
之后我們已經(jīng)將我們的文本轉(zhuǎn)換成path
對象迁杨,并將其添加到路徑層钻心,我們就可以使用下面代碼簡單添加動畫了:
let pathAnimation = CABasicAnimation(keyPath: "strokeEnd")
pathAnimation.duration = duration
pathAnimation.fromValue = 0.0
pathAnimation.toValue = 1.0
pathAnimation.delegate = self
pathLayer?.addAnimation(pathAnimation, forKey: "strokeEnd")
為了達到給文本層添加動畫的目的,一個VRMTextAnimator
類被創(chuàng)建了铅协。這個類和示范文本層動畫的示例工程在這里可以找到捷沸。
為了使用這個類,你不得不使用帶有一個reference view
的初始化方式init(referenceView:)``初始化狐史。
reference view是一種類型的視圖痒给,其中我們執(zhí)行文本動畫。
VRMTextAnimator有兩個關(guān)鍵屬性骏全,
animationLayer和
pathLayer苍柏。第一個是我們要執(zhí)行動畫的CALayer對象,第二個是CAShapeLayer對象吟温,它存儲從我們之前設(shè)定的文字創(chuàng)造了一個
CGPath對象序仙。這個類也有三個可設(shè)置的屬性:字體名稱/
fontName,字體尺寸/
fontSize鲁豪,
textToAnimate潘悼。如果我們想要動畫一個特定的文本與他的字體和字體大小律秃,我們需要設(shè)置這些屬性,
VRMTextAnimator`也有一個代理對象治唤,可以通知我們動畫的起點和終點棒动。
在這個項目中,有兩種類型的文本層動畫宾添。第一種動畫是簡單的開始按鈕觸發(fā)的船惨,第二種是通過滑塊控制的。事實證明缕陕,我們可以設(shè)置它的speed
粱锐,fromValue
,toValue
扛邑,duration
和timeOffset
屬性怜浅。如果我們設(shè)置fromValue
為0,toValue
為1蔬崩,duration
為1恶座,同時我們正在動畫pathLayer對象的strokeEnd
屬性,我們就可以通過設(shè)置pathLayer
的timeOffset
屬性來繪制文本輪廓的相應(yīng)部分沥阳。