目录:
#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