前两天下载了一个Swift的HUD提示效果,偶然发现其中的提示效果上面的文字是动态书写的。感觉挺不错的,代码地址如下:
http://code.cocoachina.com/view/129442。
然后自己使用里面部分技术写了一个OC版的,
Demo地址:https://github.com/longitachi/WritingEffect/tree/master
效果图:
Swift具体实现(仅仅贴出NSString转UIBezierPath的方法,动画简单自己加,或者下载源码):
class func bezierPathFrom(string:String) -> UIBezierPath{
let paths = CGPathCreateMutable()
let fontName = __CFStringMakeConstantString("SnellRoundhand")
let fontRef:AnyObject = CTFontCreateWithName(fontName, 18, nil)
let attrString = NSAttributedString(string: string, attributes: [kCTFontAttributeName as String : fontRef])
let line = CTLineCreateWithAttributedString(attrString as CFAttributedString)
let runA = CTLineGetGlyphRuns(line)
for (var runIndex = 0; runIndex < CFArrayGetCount(runA); runIndex++){
let run = CFArrayGetValueAtIndex(runA, runIndex);
let runb = unsafeBitCast(run, CTRun.self)
let CTFontName = unsafeBitCast(kCTFontAttributeName, UnsafePointer<Void>.self)
let runFontC = CFDictionaryGetValue(CTRunGetAttributes(runb),CTFontName)
let runFontS = unsafeBitCast(runFontC, CTFont.self)
let width = UIScreen.mainScreen().bounds.width
var temp = 0
var offset:CGFloat = 0.0
for(var i = 0; i < CTRunGetGlyphCount(runb); i++){
let range = CFRangeMake(i, 1)
let glyph:UnsafeMutablePointer<CGGlyph> = UnsafeMutablePointer<CGGlyph>.alloc(1)
glyph.initialize(0)
let position:UnsafeMutablePointer<CGPoint> = UnsafeMutablePointer<CGPoint>.alloc(1)
position.initialize(CGPointZero)
CTRunGetGlyphs(runb, range, glyph)
CTRunGetPositions(runb, range, position);
let temp3 = CGFloat(position.memory.x)
let temp2 = (Int) (temp3 / width)
let temp1 = 0
if(temp2 > temp1){
temp = temp2
offset = position.memory.x - (CGFloat(temp) * width)
}
let path = CTFontCreatePathForGlyph(runFontS,glyph.memory,nil)
let x = position.memory.x - (CGFloat(temp) * width) - offset
let y = position.memory.y - (CGFloat(temp) * 80)
var transform = CGAffineTransformMakeTranslation(x, y)
CGPathAddPath(paths, &transform, path)
glyph.destroy()
glyph.dealloc(1)
position.destroy()
position.dealloc(1)
}
}
let bezierPath = UIBezierPath()
bezierPath.moveToPoint(CGPointZero)
bezierPath.appendPath(UIBezierPath(CGPath: paths))
return bezierPath
}
根据Swift翻译的OC版本,实现如下:
- (UIBezierPath *)transformToBezierPath:(NSString *)string
{
CGMutablePathRef paths = CGPathCreateMutable();
CFStringRef fontNameRef = CFSTR("SnellRoundhand");
CTFontRef fontRef = CTFontCreateWithName(fontNameRef, 18, nil);
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:string attributes:@{(__bridge NSString *)kCTFontAttributeName: (__bridge UIFont *)fontRef}];
CTLineRef lineRef = CTLineCreateWithAttributedString((CFAttributedStringRef)attrString);
CFArrayRef runArrRef = CTLineGetGlyphRuns(lineRef);
for (int runIndex = 0; runIndex < CFArrayGetCount(runArrRef); runIndex++) {
const void *run = CFArrayGetValueAtIndex(runArrRef, runIndex);
CTRunRef runb = (CTRunRef)run;
const void *CTFontName = kCTFontAttributeName;
const void *runFontC = CFDictionaryGetValue(CTRunGetAttributes(runb), CTFontName);
CTFontRef runFontS = (CTFontRef)runFontC;
CGFloat width = [UIScreen mainScreen].bounds.size.width;
int temp = 0;
CGFloat offset = .0;
for (int i = 0; i < CTRunGetGlyphCount(runb); i++) {
CFRange range = CFRangeMake(i, 1);
CGGlyph glyph = 0;
CTRunGetGlyphs(runb, range, &glyph);
CGPoint position = CGPointZero;
CTRunGetPositions(runb, range, &position);
CGFloat temp3 = position.x;
int temp2 = (int)temp3/width;
CGFloat temp1 = 0;
if (temp2 > temp1) {
temp = temp2;
offset = position.x - (CGFloat)temp;
}
CGPathRef path = CTFontCreatePathForGlyph(runFontS, glyph, nil);
CGFloat x = position.x - (CGFloat)temp*width - offset;
CGFloat y = position.y - (CGFloat)temp * 80;
CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
CGPathAddPath(paths, &transform, path);
CGPathRelease(path);
}
CFRelease(runb);
CFRelease(runFontS);
}
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointZero];
[bezierPath appendPath:[UIBezierPath bezierPathWithCGPath:paths]];
CGPathRelease(paths);
CFRelease(fontNameRef);
CFRelease(fontRef);
return bezierPath;
}