IOS CoreText --- 图文混排
2015-05-29 09:07
495 查看
利用CORETEXT进行图文混排。
实现代码:
[cpp] view
plaincopy
void RunDelegateDeallocCallback( void* refCon ){
}
CGFloat RunDelegateGetAscentCallback( void *refCon ){
NSString *imageName = (NSString *)refCon;
return 80;//[UIImage imageNamed:imageName].size.height;
}
CGFloat RunDelegateGetDescentCallback(void *refCon){
return 0;
}
CGFloat RunDelegateGetWidthCallback(void *refCon){
NSString *imageName = (NSString *)refCon;
return 100;//[UIImage imageNamed:imageName].size.width;
}
先设置一个CTRun的委托,主要是用于指定对象的上行高,宽,或上下文释放时使用。
[cpp] view
plaincopy
-(void)drawCharAndPicture
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);//设置字形变换矩阵为CGAffineTransformIdentity,也就是说每一个字形都不做图形变换
CGAffineTransform flipVertical = CGAffineTransformMake(1,0,0,-1,0,self.bounds.size.height);
CGContextConcatCTM(context, flipVertical);//将当前context的坐标系进行flip
NSLog(@"bh=%f",self.bounds.size.height);
NSMutableAttributedString *attributedString = [[[NSMutableAttributedString alloc] initWithString:@"请在这里插入一张图片位置"] autorelease];
//为图片设置CTRunDelegate,delegate决定留给图片的空间大小
NSString *imgName = @"img.png";
CTRunDelegateCallbacks imageCallbacks;
imageCallbacks.version = kCTRunDelegateVersion1;
imageCallbacks.dealloc = RunDelegateDeallocCallback;
imageCallbacks.getAscent = RunDelegateGetAscentCallback;
imageCallbacks.getDescent = RunDelegateGetDescentCallback;
imageCallbacks.getWidth = RunDelegateGetWidthCallback;
CTRunDelegateRef runDelegate = CTRunDelegateCreate(&imageCallbacks, imgName);
NSMutableAttributedString *imageAttributedString = [[NSMutableAttributedString alloc] initWithString:@" "];//空格用于给图片留位置
[imageAttributedString addAttribute:(NSString *)kCTRunDelegateAttributeName value:(id)runDelegate range:NSMakeRange(0, 1)];
CFRelease(runDelegate);
[imageAttributedString addAttribute:@"imageName" value:imgName range:NSMakeRange(0, 1)];
[attributedString insertAttributedString:imageAttributedString atIndex:4];
[cpp] view
plaincopy
//换行模式
CTParagraphStyleSetting lineBreakMode;
CTLineBreakMode lineBreak = kCTLineBreakByCharWrapping;
lineBreakMode.spec = kCTParagraphStyleSpecifierLineBreakMode;
lineBreakMode.value = &lineBreak;
lineBreakMode.valueSize = sizeof(CTLineBreakMode);
CTParagraphStyleSetting settings[] = {
lineBreakMode
};
CTParagraphStyleRef style = CTParagraphStyleCreate(settings, 1);
// build attributes
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(id)style forKey:(id)kCTParagraphStyleAttributeName ];
// set attributes to attributed string
[attributedString addAttributes:attributes range:NSMakeRange(0, [attributedString length])];
CTFramesetterRef ctFramesetter = CTFramesetterCreateWithAttributedString((CFMutableAttributedStringRef)attributedString);
CGMutablePathRef path = CGPathCreateMutable();
CGRect bounds = CGRectMake(0.0, 0.0, self.bounds.size.width, self.bounds.size.height);
CGPathAddRect(path, NULL, bounds);
CTFrameRef ctFrame = CTFramesetterCreateFrame(ctFramesetter,CFRangeMake(0, 0), path, NULL);
CTFrameDraw(ctFrame, context);
CFArrayRef lines = CTFrameGetLines(ctFrame);
CGPoint lineOrigins[CFArrayGetCount(lines)];
CTFrameGetLineOrigins(ctFrame, CFRangeMake(0, 0), lineOrigins);
NSLog(@"line count = %ld",CFArrayGetCount(lines));
for (int i = 0; i < CFArrayGetCount(lines); i++) {
CTLineRef line = CFArrayGetValueAtIndex(lines, i);
CGFloat lineAscent;
CGFloat lineDescent;
CGFloat lineLeading;
CTLineGetTypographicBounds(line, &lineAscent, &lineDescent, &lineLeading);
NSLog(@"ascent = %f,descent = %f,leading = %f",lineAscent,lineDescent,lineLeading);
CFArrayRef runs = CTLineGetGlyphRuns(line);
NSLog(@"run count = %ld",CFArrayGetCount(runs));
for (int j = 0; j < CFArrayGetCount(runs); j++) {
CGFloat runAscent;
CGFloat runDescent;
CGPoint lineOrigin = lineOrigins[i];
CTRunRef run = CFArrayGetValueAtIndex(runs, j);
NSDictionary* attributes = (NSDictionary*)CTRunGetAttributes(run);
CGRect runRect;
runRect.size.width = CTRunGetTypographicBounds(run, CFRangeMake(0,0), &runAscent, &runDescent, NULL);
NSLog(@"width = %f",runRect.size.width);
runRect=CGRectMake(lineOrigin.x + CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, NULL), lineOrigin.y - runDescent, runRect.size.width, runAscent + runDescent);
NSString *imageName = [attributes objectForKey:@"imageName"];
//图片渲染逻辑
if (imageName) {
UIImage *image = [UIImage imageNamed:imageName];
if (image) {
CGRect imageDrawRect;
imageDrawRect.size = image.size;
imageDrawRect.origin.x = runRect.origin.x + lineOrigin.x;
imageDrawRect.origin.y = lineOrigin.y;
CGContextDrawImage(context, imageDrawRect, image.CGImage);
}
}
}
}
CFRelease(ctFrame);
CFRelease(path);
CFRelease(ctFramesetter);
}
效果:
从上面看大家可能没有发现什么问题,当把图片放在字的最左边会是什么样子的?
因此为了避免这种情况发生,我在代码中添加了换行模式。添加换行后的效果:
实现代码:
[cpp] view
plaincopy
void RunDelegateDeallocCallback( void* refCon ){
}
CGFloat RunDelegateGetAscentCallback( void *refCon ){
NSString *imageName = (NSString *)refCon;
return 80;//[UIImage imageNamed:imageName].size.height;
}
CGFloat RunDelegateGetDescentCallback(void *refCon){
return 0;
}
CGFloat RunDelegateGetWidthCallback(void *refCon){
NSString *imageName = (NSString *)refCon;
return 100;//[UIImage imageNamed:imageName].size.width;
}
先设置一个CTRun的委托,主要是用于指定对象的上行高,宽,或上下文释放时使用。
[cpp] view
plaincopy
-(void)drawCharAndPicture
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);//设置字形变换矩阵为CGAffineTransformIdentity,也就是说每一个字形都不做图形变换
CGAffineTransform flipVertical = CGAffineTransformMake(1,0,0,-1,0,self.bounds.size.height);
CGContextConcatCTM(context, flipVertical);//将当前context的坐标系进行flip
NSLog(@"bh=%f",self.bounds.size.height);
NSMutableAttributedString *attributedString = [[[NSMutableAttributedString alloc] initWithString:@"请在这里插入一张图片位置"] autorelease];
//为图片设置CTRunDelegate,delegate决定留给图片的空间大小
NSString *imgName = @"img.png";
CTRunDelegateCallbacks imageCallbacks;
imageCallbacks.version = kCTRunDelegateVersion1;
imageCallbacks.dealloc = RunDelegateDeallocCallback;
imageCallbacks.getAscent = RunDelegateGetAscentCallback;
imageCallbacks.getDescent = RunDelegateGetDescentCallback;
imageCallbacks.getWidth = RunDelegateGetWidthCallback;
CTRunDelegateRef runDelegate = CTRunDelegateCreate(&imageCallbacks, imgName);
NSMutableAttributedString *imageAttributedString = [[NSMutableAttributedString alloc] initWithString:@" "];//空格用于给图片留位置
[imageAttributedString addAttribute:(NSString *)kCTRunDelegateAttributeName value:(id)runDelegate range:NSMakeRange(0, 1)];
CFRelease(runDelegate);
[imageAttributedString addAttribute:@"imageName" value:imgName range:NSMakeRange(0, 1)];
[attributedString insertAttributedString:imageAttributedString atIndex:4];
[cpp] view
plaincopy
//换行模式
CTParagraphStyleSetting lineBreakMode;
CTLineBreakMode lineBreak = kCTLineBreakByCharWrapping;
lineBreakMode.spec = kCTParagraphStyleSpecifierLineBreakMode;
lineBreakMode.value = &lineBreak;
lineBreakMode.valueSize = sizeof(CTLineBreakMode);
CTParagraphStyleSetting settings[] = {
lineBreakMode
};
CTParagraphStyleRef style = CTParagraphStyleCreate(settings, 1);
// build attributes
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(id)style forKey:(id)kCTParagraphStyleAttributeName ];
// set attributes to attributed string
[attributedString addAttributes:attributes range:NSMakeRange(0, [attributedString length])];
CTFramesetterRef ctFramesetter = CTFramesetterCreateWithAttributedString((CFMutableAttributedStringRef)attributedString);
CGMutablePathRef path = CGPathCreateMutable();
CGRect bounds = CGRectMake(0.0, 0.0, self.bounds.size.width, self.bounds.size.height);
CGPathAddRect(path, NULL, bounds);
CTFrameRef ctFrame = CTFramesetterCreateFrame(ctFramesetter,CFRangeMake(0, 0), path, NULL);
CTFrameDraw(ctFrame, context);
CFArrayRef lines = CTFrameGetLines(ctFrame);
CGPoint lineOrigins[CFArrayGetCount(lines)];
CTFrameGetLineOrigins(ctFrame, CFRangeMake(0, 0), lineOrigins);
NSLog(@"line count = %ld",CFArrayGetCount(lines));
for (int i = 0; i < CFArrayGetCount(lines); i++) {
CTLineRef line = CFArrayGetValueAtIndex(lines, i);
CGFloat lineAscent;
CGFloat lineDescent;
CGFloat lineLeading;
CTLineGetTypographicBounds(line, &lineAscent, &lineDescent, &lineLeading);
NSLog(@"ascent = %f,descent = %f,leading = %f",lineAscent,lineDescent,lineLeading);
CFArrayRef runs = CTLineGetGlyphRuns(line);
NSLog(@"run count = %ld",CFArrayGetCount(runs));
for (int j = 0; j < CFArrayGetCount(runs); j++) {
CGFloat runAscent;
CGFloat runDescent;
CGPoint lineOrigin = lineOrigins[i];
CTRunRef run = CFArrayGetValueAtIndex(runs, j);
NSDictionary* attributes = (NSDictionary*)CTRunGetAttributes(run);
CGRect runRect;
runRect.size.width = CTRunGetTypographicBounds(run, CFRangeMake(0,0), &runAscent, &runDescent, NULL);
NSLog(@"width = %f",runRect.size.width);
runRect=CGRectMake(lineOrigin.x + CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, NULL), lineOrigin.y - runDescent, runRect.size.width, runAscent + runDescent);
NSString *imageName = [attributes objectForKey:@"imageName"];
//图片渲染逻辑
if (imageName) {
UIImage *image = [UIImage imageNamed:imageName];
if (image) {
CGRect imageDrawRect;
imageDrawRect.size = image.size;
imageDrawRect.origin.x = runRect.origin.x + lineOrigin.x;
imageDrawRect.origin.y = lineOrigin.y;
CGContextDrawImage(context, imageDrawRect, image.CGImage);
}
}
}
}
CFRelease(ctFrame);
CFRelease(path);
CFRelease(ctFramesetter);
}
效果:
从上面看大家可能没有发现什么问题,当把图片放在字的最左边会是什么样子的?
因此为了避免这种情况发生,我在代码中添加了换行模式。添加换行后的效果:
相关文章推荐
- IOS CoreText --- 段落样子CTParagraphStyle
- IOS CoreText --- 行 CTLineRef
- IOS CoreText --- 基本用法
- ios 手势
- IOS 开发学习28 NSArray 基本用法
- iOS 逆向之ARM汇编
- iOS开发笔记18--SEL (@selector) 原理及使用总结(二)
- iOS开发笔记17-SEL (@selector) 原理及使用总结(一)
- iOS开发笔记16--第三方登陆
- 解决Xcode package manager无法使用
- ios开发-日期处理(类似朋友圈,微博等的发送时间)
- ios与js交互,获取webview完整url,title,获取元素并赋值跳转
- ios时间与日期的处理
- 浅谈iOS面向对象之类与对象
- ios动画学习(一)
- iOS将汉字转化成oc字符串
- iOS开发-retain/assign/strong/weak/copy/mutablecopy/autorelease区别
- iOS - 中三种定时器的用法NSTimer、CADisplayLink、GCD
- IOS 6 自动布局 入门-1
- 控制器View的生命周期图解