On this issue, I have already mentioned in another blog:
Coretext a little improvement in the animation of wonderful text contour drawing
However, the original conversion code is written using Obj-c, where we try to convert it to the swift language and then use it to implement a Test applet.
First put the original OBJC code:
- (void) setuptextlayer{if( Self. Pathlayer!=Nil) { [ Self. PenlayerRemovefromsuperlayer]; [ Self. PathlayerRemovefromsuperlayer]; 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.aspxCgmutablepathref letters = cgpathcreatemutable (); Ctfontref font = ctfontcreatewithname (Cfstr ("Helvetica-bold"),72.0FNULL);nsdictionary*attrs = [nsdictionaryDictionarywithobjectsandkeys: (ID) Font, Kctfontattributename,Nil]; nsattributedstring *attrstring = [[Nsattributedstring alloc] initwithstring:@"Hello, panda patty!" //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 runCtrunref 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-dataCfrange Thisglyphrange = Cfrangemake (Runglyphindex,1); Cgglyph Glyph;CgpointPosition 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= [[UicolorBlackcolor] Cgcolor]; Pathlayer. FillColor=Nil; Pathlayer. LineWidth=5.0F//pathlayer.linejoin = kcalinejoinbevel;Pathlayer. LineJoin= Kcalinejoinmiter; [ Self. AnimationlayerAddsublayer:pathlayer]; Self. Pathlayer= Pathlayer;//happy Commit NSLog(@"Hello World!!!");//uiimage *penimage = [UIImage imagenamed:@ "Noun_project_347_2.png"]; UIImage*penimage = [UIImageimagenamed:@"Bee.png"]; Calayer *penlayer = [Calayer layer]; Penlayer. Contents= (ID) Penimage. Cgimage; Penlayer. Anchorpoint= Cgpointzero; Penlayer. Frame= CGRectMake (0.0F0.0F, Penimage. Size. Width/5, Penimage. Size. Height/5); [Pathlayer Addsublayer:penlayer]; Self. Penlayer= Penlayer;}
It looks quite long! But don't take it too seriously, because we're going to use Swift's rewrite code to extract only the middle part of it, so it's better reused.
Create a new project, based on the swift language.
Create a new Swift source code file in the project that extends the string class, and we write a stub for the helper method in its extension:
extension String{ func toPath(font:CTFont)->CGPath{ }}
The Topath method is used to convert any string instance to the Cgpath path, adding the following content:
LetLetters:cgmutablepathref = Cgpathcreatemutable () LetAttrs = [Kctfontattributename asString:font] Letattrstring:nsattributedstring = nsattributedstring (string: Self, attributes:attrs) LetLine:ctline = ctlinecreatewithattributedstring (attrstring) LetRunarray = Ctlinegetglyphruns (line) forRunindexinch 0.. <cfarraygetcount (Runarray) { LetRun = Cfarraygetvalueatindex (Runarray, Runindex) LetRunb = Unsafebitcast (run, ctrun.self)//let Runfont:ctfont = Cfdictionarygetvalue (Ctrungetattributes (RUNB), kctfontattributename as String) as! Ctfont LetCtfontname = Unsafebitcast (Kctfontattributename, unsafepointer<void>.self) LetRUNFONTC = Cfdictionarygetvalue (Ctrungetattributes (RUNB), ctfontname) LetRunfont = Unsafebitcast (RUNFONTC, ctfont.self)//for each GLYPH in run forRunglyphindexinch 0.. <ctrungetglyphcount (RUNB) {//get Glyph & Glyph-data LetGlyphrange = Cfrange (location:runglyphindex, Length:1)//let glyph:unsafemutablepointer<cgglyph> = unsafemutablepointer<cgglyph>.alloc (1) //glyph.initialize (0) varGlyph:cgglyph =0 Letposition: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) LetLetter = Ctfontcreatepathforglyph (Runfont, glyph, Nil)vart = 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) } } LetPath = Uibezierpath () path.movetopoint (Cgpoint.zero) Path.appendpath (Uibezierpath (cgpath:letters))returnPath. Cgpath
We can look at the original version of Obj-c, roughly one by one corresponding, only a few of the operation of C language data where there are changes, we can refer to another blog I wrote:
How to convert different types of mutable pointers in Swift
The core function has, the following is good to do! What we want is to click on the screen to start the animation, and then overload the following methods:
Override Func touchesended (touches:Set<uitouch>, Withevent event:uievent?) {if isanimating {return} isanimating = True Flyerlayer. Opacity=0.8Pathlayer. Removeallanimations() Flyerlayer. Removeallanimations() Let strokeanimation = Cabasicanimation (keypath:"Strokeend") strokeanimation. Duration=20.0Strokeanimation. Fromvalue=0.0Strokeanimation. Tovalue=1.0Strokeanimation. Delegate= Self Pathlayer. Addanimation(Strokeanimation, forkey:nil) Let flyanimation = Cakeyframeanimation (keypath:"Position") flyanimation. Duration=20.0Flyanimation. Path= Pathlayer. PathFlyanimation. Calculationmode= kcaanimationpaced Flyerlayer. Addanimation(Flyanimation, Forkey:nil)}
Here's how the app actually works:
Converts a string to its represented path on the screen