Created
August 8, 2016 08:35
-
-
Save skyline75489/4c2bf228263eacfa133de4c8a468469b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSAttributedString+CoreTextHelper.m | |
// TutorTeacherHD | |
// | |
// Created by skyline on 16/8/8. | |
// Copyright © 2016年 skyline. All rights reserved. | |
// | |
#import "NSAttributedString+CoreTextHelper.h" | |
#import <CoreText/CoreText.h> | |
#import <objc/runtime.h> | |
static char lastLineWidthCacheKey; | |
static char lineCountCacheKey; | |
@implementation NSAttributedString (CoreTextHelper) | |
- (NSMutableDictionary *)lastLineWidthCache { | |
NSMutableDictionary *cache = objc_getAssociatedObject(self, &lastLineWidthCacheKey); | |
if (cache) { | |
return cache; | |
} | |
cache = [NSMutableDictionary dictionary]; | |
objc_setAssociatedObject(self, &lastLineWidthCacheKey, cache, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
return cache; | |
} | |
- (NSMutableDictionary *)lineCountCache { | |
NSMutableDictionary *cache = objc_getAssociatedObject(self, &lineCountCacheKey); | |
if (cache) { | |
return cache; | |
} | |
cache = [NSMutableDictionary dictionary]; | |
objc_setAssociatedObject(self, &lineCountCacheKey, cache, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
return cache; | |
} | |
- (NSString *)cacheStoreKeyWithRect:(CGRect)rect { | |
return [NSString stringWithFormat:@"%@_%@", self.string, NSStringFromCGRect(rect)]; | |
} | |
- (CGFloat)lastLineWidthWithBoundingRect:(CGRect)rect { | |
NSNumber *cachedValue = [self.lastLineWidthCache objectForKey:[self cacheStoreKeyWithRect:rect]]; | |
if (cachedValue) { | |
#if CGFLOAT_IS_DOUBLE | |
return [cachedValue doubleValue]; | |
#else | |
return [cachedValue floatValue]; | |
#endif | |
} | |
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFMutableAttributedStringRef)self); | |
CGMutablePathRef path = CGPathCreateMutable(); | |
CGPathAddRect(path, NULL, rect); | |
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL); | |
CFArrayRef lines = CTFrameGetLines(frame); | |
NSInteger lineCount = CFArrayGetCount(lines); | |
[self.lineCountCache setObject:@(lineCount) forKey:[self cacheStoreKeyWithRect:rect]]; | |
CTLineRef lastLine = CFArrayGetValueAtIndex(lines, MAX(lineCount - 1, 0)); | |
CGFloat ascent; | |
CGFloat descent; | |
CGFloat leading; | |
#if CGFLOAT_IS_DOUBLE | |
double lineWidth = CTLineGetTypographicBounds(lastLine, &ascent, &descent, &leading); | |
#else | |
CGFloat lineWidth = (CGFloat)CTLineGetTypographicBounds(lastLine, &ascent, &descent, &leading); | |
#endif | |
[self.lastLineWidthCache setObject:@(lineWidth) forKey:[self cacheStoreKeyWithRect:rect]]; | |
CFRelease(path); | |
CFRelease(frame); | |
CFRelease(framesetter); | |
return lineWidth; | |
} | |
- (NSInteger)lineCountWithBoundingRect:(CGRect)rect { | |
NSNumber *cachedValue = [self.lineCountCache objectForKey:[self cacheStoreKeyWithRect:rect]]; | |
if (cachedValue) { | |
return [cachedValue integerValue]; | |
} | |
return -1; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment