标签:getc image uiimage ade 判断 draw height gre def
CTFrame作为一个整体的画布,其中由行(CTLine)组成,每行可以分为一个或多个小方块(CTRun),属性一样的字符就分在一个小方块里。
因为绘制只是显示,其他需要的额外操作,如响应相关点击事件原理:CTFrame包含了多个CTLine,并且可以得到每个line的起始位置与大小,计算出你响应的区域范围,然后根据你点击的坐标来判断是否在响应区。再如图片显示原理:先用空白占位符来把位置留出来,然后再添加图片
富文本绘制步骤:
@interface EOCTextLabel() {
NSRange sepRange;
CGRect sepRect;
}
@end
@implementation EOCTextLabel
- (void)drawRect:(CGRect)rect {
sepRange = NSMakeRange(30, 5);
NSMutableAttributedString *attriStr = [[NSMutableAttributedString alloc] initWithString:self.text attributes:nil];
[attriStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16] range:NSMakeRange(0, self.text.length)];
[attriStr addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:sepRange];
CGContextRef context = UIGraphicsGetCurrentContext();
//生成frame
CTFramesetterRef frameset = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attriStr);
CGPathRef path = CGPathCreateWithRect(CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), &CGAffineTransformIdentity);
CTFrameRef frame = CTFramesetterCreateFrame(frameset, CFRangeMake(0, 0), path, nil);
//调整坐标
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.frame.size.height);
CGContextScaleCTM(context, 1, -1);
//绘制
CTFrameDraw(frame, context);
}
事件添加步骤
判断事件的点击位置是否处于rect中,如果是则触发事件
- (void)drawRect:(CGRect)rect {
//...绘制
//获取信息
NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame);
CGPoint pointArray[lines.count];
memset(pointArray, 0, sizeof(pointArray));
//由于坐标系的关系,不直接通过这种方式拿行(CTLine)的起始位置
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), pointArray);
double heightAddup = 0;
//CTLine信息获取
for (int i=0; i<lines.count; i++) {
CTLineRef line = (__bridge CTLineRef)lines[i];
NSArray *runs = (__bridge NSArray *)CTLineGetGlyphRuns(line);
CGFloat ascent = 0;
CGFloat descent = 0;
CGFloat lineGap = 0;
CTLineGetTypographicBounds(line, &ascent, &descent, &lineGap);
double runHeight = ascent + descent + lineGap;
double startX = 0;
//CTRun信息获取
for (int j=0; j<runs.count; j++) {
CTRunRef run = (__bridge CTRunRef)runs[j];
CFRange runRange = CTRunGetStringRange(run);
double runWidth = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), 0, 0, 0);
if (runRange.location == sepRange.location && runRange.length == sepRange.length) {
//计算我们需要的位置和size,即rect
NSLog(@"找到了");
NSLog(@"%f, %f, %f, %f", startX, heightAddup, runWidth, runHeight);
sepRect = CGRectMake(startX, heightAddup, runWidth, runHeight);
//只有点击第三个字符时才会触发
//sepRect = CGRectMake(startX+runWidth*2/5, heightAddup, runWidth/5, runHeight);
}
startX += runWidth;
}
//字的高度叠加
heightAddup += runHeight;
NSLog(@"%f====%f", pointArray[i].y, heightAddup);
}
//添加button按钮和事件也可以达到需求要求
[self setNeedsLayout];
}
- (void)layoutSubviews {
if (sepRect.size.width>0) {
}
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
if (CGRectContainsPoint(sepRect, point)) {
NSLog(@"点击");
}
}
图文混排步骤
调用[self setNeedsLayout]后自动layoutSubviews,设置ImageView的位置和图片
#define EOCCoreTextImageWidthPro @"EOCCoreTextImageWidthPro"
#define EOCCoreTextImageHeightPro @"EOCCoreTextImageHeightPro"
static CGFloat ctRunDelegateGetWidthCallback(void *refCon) {
NSDictionary *infoDic = (__bridge NSDictionary *)refCon;
if ([infoDic isKindOfClass:[NSDictionary class]]) {
return [infoDic[EOCCoreTextImageWidthPro] floatValue];
}
return 0;
}
static CGFloat ctRunDelegateGetAscentCallback(void *refCon) {
NSDictionary *infoDic = (__bridge NSDictionary *)refCon;
if ([infoDic isKindOfClass:[NSDictionary class]]) {
return [infoDic[EOCCoreTextImageHeightPro] floatValue];
}
return 0;
}
static CGFloat ctRunDelegateGetDescentCallback(void *refCon) {
return 0;
}
@interface EOCImageLabel() {
NSInteger ImageSpaceIndex;
CGRect sepRect;
UIImageView *_eocImageV;
}
@end
@implementation EOCImageLabel
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
ImageSpaceIndex = self.text.length;
NSMutableAttributedString *attriStr = [[NSMutableAttributedString alloc] initWithString:self.text attributes:nil];
[attriStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16] range:NSMakeRange(0, self.text.length)];
//图片占位符添加
NSMutableAttributedString *attriImageSpaceStr = [self sepImageSpaceWithWidth:100 height:50];
[attriStr appendAttributedString:attriImageSpaceStr];
NSMutableAttributedString *attriTailStr = [[NSMutableAttributedString alloc] initWithString:@"123456789" attributes:nil];
[attriStr appendAttributedString:attriTailStr];
CGContextRef context = UIGraphicsGetCurrentContext();
//生成frame
CTFramesetterRef frameset = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attriStr);
CGPathRef path = CGPathCreateWithRect(CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), &CGAffineTransformIdentity);
CTFrameRef frame = CTFramesetterCreateFrame(frameset, CFRangeMake(0, 0), path, nil);
//调整坐标
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.frame.size.height);
CGContextScaleCTM(context, 1, -1);
//绘制
CTFrameDraw(frame, context);
//获取信息
NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame);
CGPoint pointArray[lines.count];
memset(pointArray, 0, sizeof(pointArray));
//由于坐标系的关系,不直接通过这种方式拿行(CTLine)的起始位置
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), pointArray);
double heightAddup = 0;
//CTLine信息获取
for (int i=0; i<lines.count; i++) {
CTLineRef line = (__bridge CTLineRef)lines[i];
NSArray *runs = (__bridge NSArray *)CTLineGetGlyphRuns(line);
CGFloat ascent = 0;
CGFloat descent = 0;
CGFloat lineGap = 0;
CTLineGetTypographicBounds(line, &ascent, &descent, &lineGap);
double runHeight = ascent + descent + lineGap;
double startX = 0;
//CTRun信息获取
for (int j=0; j<runs.count; j++) {
CTRunRef run = (__bridge CTRunRef)runs[j];
CFRange runRange = CTRunGetStringRange(run);
double runWidth = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), 0, 0, 0);
if (ImageSpaceIndex==runRange.location && ImageSpaceIndex < runRange.location + runRange.length) {
//计算我们需要的位置和size,即rect
NSLog(@"找到了");
NSLog(@"%f, %f, %f, %f", startX, heightAddup, runWidth, runHeight);
sepRect = CGRectMake(startX, heightAddup, runWidth, runHeight);
//只有点击第三个字符时才会触发
//sepRect = CGRectMake(startX+runWidth*2/5, heightAddup, runWidth/5, runHeight);
}
startX += runWidth;
}
//字的高度叠加
heightAddup += runHeight;
NSLog(@"%f====%f", pointArray[i].y, heightAddup);
}
//添加button按钮和事件也可以达到需求要求
[self setNeedsLayout];
}
- (void)layoutSubviews {
if (sepRect.size.width>0) {
_eocImageV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"0.png"]];
[self addSubview:_eocImageV];
}
_eocImageV.frame = sepRect;
}
- (NSMutableAttributedString *)sepImageSpaceWithWidth:(float)width height:(float)height {
//创建占位符
NSMutableAttributedString *spaceAttribut = [[NSMutableAttributedString alloc] initWithString:@" " attributes:nil];
//配置占位符的属性
CTRunDelegateCallbacks callbacks;
memset(&callbacks, 0, sizeof(CTRunDelegateCallbacks));
callbacks.getAscent = ctRunDelegateGetAscentCallback;
callbacks.getDescent = ctRunDelegateGetDescentCallback;
callbacks.getWidth = ctRunDelegateGetWidthCallback;
callbacks.version = kCTRunDelegateCurrentVersion;
static NSMutableDictionary *argDic = nil;
argDic = [[NSMutableDictionary alloc] init];
[argDic setValue:@(width) forKey:EOCCoreTextImageWidthPro];
[argDic setValue:@(height) forKey:EOCCoreTextImageHeightPro];
CTRunDelegateRef runDelegate = CTRunDelegateCreate(&callbacks, (__bridge void*)argDic);
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)spaceAttribut, CFRangeMake(0, 1), kCTRunDelegateAttributeName, runDelegate);
return spaceAttribut;
}
原文:大专栏 图文混排原理实现及应用
标签:getc image uiimage ade 判断 draw height gre def
原文地址:https://www.cnblogs.com/petewell/p/11614895.html