目錄:ui
#import <Foundation/Foundation.h> //用於配置繪製的參數,例如文字顏色,大小,行間距 @interface CTFrameParserConfig : NSObject @property (nonatomic,assign)CGFloat width; @property (nonatomic,assign)CGFloat fontSize; @property (nonatomic,assign)CGFloat lineSpace; @property (nonatomic,strong)UIColor *textColor; @end #import "CTFrameParserConfig.h" @implementation CTFrameParserConfig -(id)init{ self = [super init]; if (self){ _width = 200.0f; _fontSize = 16.0f; _lineSpace = 0.0f; _textColor = RGB(150, 100, 100); } return self; } @end
#import <Foundation/Foundation.h> #import "CTFrameParserConfig.h" #import "CoreTextData.h" //用於最後繪製界面須要的CTFrameRef實例 @interface CTFrameParser : NSObject +(CoreTextData *)parseContext:(NSString *)context config:(CTFrameParserConfig *)config; +(NSDictionary *)attributesWithConfig:(CTFrameParserConfig *)config; @end #import "CTFrameParser.h" @implementation CTFrameParser +(NSDictionary *)attributesWithConfig:(CTFrameParserConfig *)config{ CGFloat fontSize = config.fontSize; CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL); CGFloat lineSpacing = config.lineSpace; const CFIndex kNumberOfSettings = 3; CTParagraphStyleSetting theSettings[kNumberOfSettings] = {{kCTParagraphStyleSpecifierLineSpacingAdjustment,sizeof(CGFloat),&lineSpacing}, {kCTParagraphStyleSpecifierMaximumLineSpacing,sizeof(CGFloat),&lineSpacing}, {kCTParagraphStyleSpecifierMinimumLineSpacing,sizeof(CGFloat),&lineSpacing}}; CTParagraphStyleRef theParagrapRef = CTParagraphStyleCreate(theSettings, kNumberOfSettings); UIColor *textColor = config.textColor; NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[(id)kCTForegroundColorAttributeName] = (id)textColor.CGColor; dict[(id)kCTFontAttributeName] = (__bridge id)fontRef; dict[(id)kCTParagraphStyleAttributeName] = (__bridge id)theParagrapRef; CFRelease(theParagrapRef); CFRelease(fontRef); return dict; } +(CoreTextData *)parseContext:(NSString *)context config:(CTFrameParserConfig *)config{ NSDictionary *attributes = [self attributesWithConfig:config]; NSAttributedString *contextString = [[NSAttributedString alloc]initWithString:context attributes:attributes]; CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)contextString); //得到要繪製區域的高度 CGSize restrictSize = CGSizeMake(config.width, CGFLOAT_MAX); CGSize coreTextSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), nil, restrictSize, nil); CGFloat textHeight = coreTextSize.height; CTFrameRef frame = [self createFrameWithFramesetter:framesetter config:config height:textHeight]; //將生成好的CTFrameRef實例和計算好的的繪製高度保存到CoreTectData實例中,最後返回CoreTectData實例 CoreTextData *data = [[CoreTextData alloc]init]; data.ctFrame =frame; data.height = textHeight; CFRelease(frame); CFRelease(framesetter); return data; } +(CTFrameRef)createFrameWithFramesetter:(CTFramesetterRef)framesetter config:(CTFrameParserConfig *)config height:(CGFloat)height{ //建立繪製的區域 CGMutablePathRef path = CGPathCreateMutable(); // CGPathAddRect(path, NULL, CGRectMake(0, 0, config.width, height)); CGPathAddRect(path, NULL, CGRectMake(0, -250, config.width+100, 200));//相反於UIKit,底層座標 CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL); CFRelease(path); return frame; } @end
#import <Foundation/Foundation.h> //保存CTFrameParser類生成的CTFrameRef,以及CTFrameRef實質繪製須要的高度 @interface CoreTextData : NSObject @property (nonatomic ,assign)CTFrameRef ctFrame; @property (nonatomic ,assign)CGFloat height;//實際使用場景彙總,須要先知道索要顯示內容的高度以後才能夠進行繪製 @end #import "CoreTextData.h" @implementation CoreTextData -(void)setCtFrame:(CTFrameRef)ctFrame{ if (_ctFrame != ctFrame){ if (_ctFrame !=nil){ CFRelease(_ctFrame); } CFRetain(ctFrame); _ctFrame = ctFrame; } } -(void)dealloc{ if (_ctFrame != nil){ CFRelease(_ctFrame); _ctFrame = nil; } } @end
#import <Foundation/Foundation.h> #import "CoreTextData.h" //持有CoreTextData的實例,負責將CTFrameRef繪製到界面上 @interface CTSubDisplayView : UIView @property (strong,nonatomic) CoreTextData *data; @end #import "CTSubDisplayView.h" @implementation CTSubDisplayView -(void)drawRect:(CGRect)rect{ [super drawRect:rect]; //獲得當前繪製畫布的上下文,用於後續將內容繪製在畫布上 CGContextRef context = UIGraphicsGetCurrentContext(); //將座標系上線翻轉。對於底層的繪製引擎來講,屏幕的左下角是(0,0)座標。而對於在上層的UIKit來講,左上角是(0,0)座標。代碼註釋後效果如圖1. CGContextSetTextMatrix(context, CGAffineTransformIdentity); CGContextTranslateCTM(context, 100, 100);// 設置UIKit x,y CGContextScaleCTM(context, 1.0, -1.0);//拉寬,拉高 if (self.data){ CTFrameDraw(self.data.ctFrame, context); } } @end
// PrefixHeader.pch #ifndef PrefixHeader_pch #define PrefixHeader_pch // Include any system framework and library headers here that should be included in all compilation units. // You will also need to set the Prefix Header build setting of one or more of your targets to reference this file. /* iOS other 中 pch文件 將building setting中prefix header 路徑設置$(SRCROOT)/$(PROJECT_NAME)/PrefixHeader.pch */ //NSLog and UIColor #import <UIKit/UIKit.h> #import <CoreText/CoreText.h> #import "CTFrameParserConfig.h" #import "UIView+frameAdjust.h" #ifdef DEBUG #define debuglog(...) NSLog(__VA_ARGS__) #define debugMethod() NSLog(@"%s",__func__) #else #define debugLog(...) #define debugMethod() #endif #define RGB(A,B,C) [UIColor colorWithRed:A/255.0 green:B/255.0 blue:C/255.0 alpha:1.0] #endif /* PrefixHeader_pch */
#import <UIKit/UIKit.h> @interface UIView (frameAdjust) -(CGFloat)x; -(void)setX:(CGFloat)x; -(CGFloat)y; -(void)setY:(CGFloat)y; -(CGFloat)height; -(void)setHeight:(CGFloat)height; -(CGFloat)width; -(void)setWidth:(CGFloat)width; @end #import "UIView+frameAdjust.h" @implementation UIView (frameAdjust) -(CGFloat)x{ return self.frame.origin.x; } -(void)setX:(CGFloat)x{ self.frame = CGRectMake(x, self.y, self.width, self.height); } -(CGFloat)y{ return self.frame.origin.y; } -(void)setY:(CGFloat)y{ self.frame = CGRectMake(self.x, y, self.width, self.height); } -(CGFloat)height{ return self.frame.size.height; } -(void)setHeight:(CGFloat)height{ self.frame = CGRectMake(self.x, self.y, self.width, height); } -(CGFloat)width{ return self.frame.size.width; } -(void)setWidth:(CGFloat)width{ self.frame = CGRectMake(self.x, self.y, width, self.height); } @end
#import <UIKit/UIKit.h> #import "CTSubDisplayView.h" #import "CTFrameParserConfig.h" @interface ViewController : UIViewController @property (nonatomic ,strong) CTSubDisplayView *ctView; @end #import "ViewController.h" #import "CTFrameParser.h" #import "CoreTextData.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; CTFrameParserConfig *config = [[CTFrameParserConfig alloc]init]; config.textColor = [UIColor redColor]; config.width = self.ctView.width; //定製排版文件格式 NSString *content = @"讓CTFrameParser 支持接收NSAttributedString做爲參數"; NSDictionary *attr = [CTFrameParser attributesWithConfig:config]; NSMutableAttributedString *attributesString = [[NSMutableAttributedString alloc]initWithString:content attributes:attr]; [attributesString addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(0, 7)]; // CoreTextData *data = [CTFrameParser parseContext:@"按照以上原則,咱們將‘CTSubDisplayView’中的部份內容拆分" config:config]; CoreTextData *data = [CTFrameParser parseContext:content config:config];//顏色未生效 self.ctView.data = data; self.ctView.height = data.height; self.ctView.backgroundColor = [UIColor yellowColor]; self.view = self.ctView; } -(CTSubDisplayView *)ctView{ if (!_ctView){ _ctView = [[CTSubDisplayView alloc]init]; } return _ctView; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end