CoreText使用(2)图文混排
来源:互联网 发布:86joy平台 网络 编辑:程序博客网 时间:2024/06/06 03:07
在一个UIVIew的子空间上实现图文混排。支持本地图片和网络图片显示 不支持图片点击监听的功能。
图片绘制
下载图片的方法
这里涉及到几个点,
CoreText从绘制纯文本到绘制图片 使用NSAttributedString 但是图片实现是用一个空白字符作为NSAttributedString的占位符 然后设置代理 告诉Core Text给该占位字符留出一定宽度高度 最后把图片绘制到预留位置。
思路:
网络图片没有下载完 先绘制占位图片 为了方便 占位图直接使用一张本地图片。然后去下载图片 等下再完成 调用uiview的setNeedDisplay进行重绘。
需要注意:本地图片可以拿到其宽度和高度 对于网络图片 在下载完成之后不知道宽度高度 往往会采用在url后面拼接上宽度高度信息方式来处理。
绘制文本上一篇已经说过了,不再赘述。今天关注点主要在图片上。
直接给出绘制的代码:
drawRect方法
-(void)drawRect:(CGRect)rect{// NSLog(@"%@",rect); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetTextMatrix(context, CGAffineTransformIdentity); CGContextConcatCTM(context, CGAffineTransformMake(1, 0, 0, -1, 0, self.bounds.size.height)); CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, self.bounds); //文本 NSString * str = @"小戎俴收,五楘梁辀。游环胁驱,阴靷鋈续。文茵畅毂,驾我骐馵。言念君子,温其如玉。在其板屋,乱我心曲"; NSMutableAttributedString * attr = [[NSMutableAttributedString alloc]initWithString:str]; [attr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:30] range:NSMakeRange(0, 6)]; // 两种方式皆可 [attr addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(3, 10)]; [attr addAttribute:(id)kCTForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(0, 2)]; #pragma mark -- 本地图片设置部分 NSString * imageHolder = @"xiaopang.jpg"; //代理结构体初始化 CTRunDelegateCallbacks imageCallbacks; imageCallbacks.version = kCTRunDelegateVersion1; imageCallbacks.dealloc = myRunDelegateDeallocCallback; imageCallbacks.getAscent = myRunDelegateGetAscentCallback; imageCallbacks.getDescent =myRunDelegateGetDscentCallback; imageCallbacks.getWidth = myRunDelegateGetWidthCallback; //构建CTRun的代理 CTRunDelegateRef delegate = CTRunDelegateCreate(&imageCallbacks, (__bridge void * _Nullable)(imageHolder)); //构建占位属性文本 NSMutableAttributedString * imgeAttr = [[NSMutableAttributedString alloc]initWithString:@" "]; //设置占位属性文本的代理为delegate [imgeAttr addAttribute:kCTRunDelegateAttributeName value:(__bridge id)delegate range:NSMakeRange(0,1)]; CFRelease(delegate); //这个是作为id选择器的 [imgeAttr addAttribute:@"imageName" value:imageHolder range:NSMakeRange(0, 1)]; //将占位属性文本插入到文本中去。 [attr insertAttributedString:imgeAttr atIndex:5]; // 图片信息字典 NSString *picURL =@"http://img3.imgtn.bdimg.com/it/u=1811953530,4106413237&fm=206&gp=0.jpg"; NSDictionary *imgInfoDic = @{@"width":@192,@"height":@277}; // 宽高跟具体图片有关 // 设置CTRun的代理 CTRunDelegateRef mydelegate = CTRunDelegateCreate(&imageCallbacks, (__bridge void *)imgInfoDic); // 使用0xFFFC作为空白的占位符 unichar objectReplacementChar = 0xFFFC; NSString *content = [NSString stringWithCharacters:&objectReplacementChar length:1]; NSMutableAttributedString *space = [[NSMutableAttributedString alloc] initWithString:content]; [space addAttribute:kCTRunDelegateAttributeName value:(__bridge id _Nonnull)(mydelegate) range:NSMakeRange(0, 1)]; [space addAttribute:@"imageName" value:picURL range:NSMakeRange(0, 1)]; [space addAttribute:@"dict" value:imgInfoDic range:NSMakeRange(0, 1)]; CFRelease(mydelegate); // 将创建的空白AttributedString插入进当前的attrString中,位置可以随便指定,不能越界 [attr insertAttributedString:space atIndex:10]; CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attr); _frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [attr length]), path, NULL); CTFrameDraw(_frame, context); //图片绘制逻辑 [self drawAttachments]; // CFRelease(_frame); CFRelease(framesetter); CFRelease(path);}代理方法:
void myRunDelegateDeallocCallback(void *refCon){ NSLog(@"%@",@"Rundelegate dealloc");}CGFloat myRunDelegateGetDscentCallback(void *refCon){ NSLog(@"%@",@"get descent"); return 0;}#pragma mark -- 获取宽度CGFloat myRunDelegateGetWidthCallback(void *refCon){ NSLog(@"%@",@"get width");// return 10; NSString *imageName = (__bridge NSString *)refCon; if ([imageName isKindOfClass:[NSString class]]) { // 本地图片 return [UIImage imageNamed:imageName].size.width; } // 对应网络图片 return [[(__bridge NSDictionary *)refCon objectForKey:@"width"] floatValue];}#pragma mark -- 获取高度CGFloat myRunDelegateGetAscentCallback(void *refCon){ NSLog(@"%@",@"get ascent");// return 30; NSString *imageName = (__bridge NSString *)refCon; if ([imageName isKindOfClass:[NSString class]]) { // 对应本地图片 return [UIImage imageNamed:imageName].size.height; } // 对应网络图片 return [[(__bridge NSDictionary *)refCon objectForKey:@"height"] floatValue];}
图片绘制
-(void)drawAttachments{ CGContextRef context = UIGraphicsGetCurrentContext(); CFArrayRef lines = CTFrameGetLines(_frame); CFIndex lineCount = CFArrayGetCount(lines); CGPoint lineOrigins[lineCount]; CTFrameGetLineOrigins(_frame, CFRangeMake(0, 0), lineOrigins); for (CFIndex i = 0; i < lineCount; i ++) { CTLineRef line = CFArrayGetValueAtIndex(lines, i); CGPoint origin = lineOrigins[i]; CGFloat lineAscent; CGFloat lineDescent; CTLineGetTypographicBounds(line, &lineAscent, &lineDescent, NULL); CFArrayRef runs = CTLineGetGlyphRuns(line); for (int j = 0; j < CFArrayGetCount(runs); j ++) { //遍历run CGFloat runAscent; CGFloat runDescent; CTRunRef curRun = CFArrayGetValueAtIndex(runs, j); NSDictionary * attrs = (NSDictionary *)CTRunGetAttributes(curRun); CGRect runRect; runRect.size.width = CTRunGetTypographicBounds(curRun, CFRangeMake(0, 0), &lineAscent, &lineDescent, NULL); runRect = CGRectMake(origin.x + CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(curRun).location, NULL), origin.y - runDescent, runRect.size.width, runAscent + runDescent); NSString * name = [attrs objectForKey:@"imageName"]; NSLog(@"name == %@",name); if ([name isKindOfClass:[NSString class]]) { if ([name isEqualToString:@"xiaopang.jpg"]) { //绘制本地图片 UIImage *img = [UIImage imageNamed:name]; CGRect imgDrawRect; imgDrawRect.size = img.size; imgDrawRect.origin.x = runRect.origin.x; imgDrawRect.origin.y = origin.y; CGContextDrawImage(context, imgDrawRect, img.CGImage); NSLog(@"%@",NSStringFromCGRect(imgDrawRect)); } else{ NSLog(@"绘制网络图片"); CTRunDelegateRef del = (__bridge CTRunDelegateRef)[attrs objectForKey:(__bridge id)kCTRunDelegateAttributeName]; if (!del) { break; } UIImage * image; if (!_myImage) { image = [UIImage imageNamed:@"xiaopang.jpg"]; [self downloadImageWithURL:[NSURL URLWithString:name]]; } else{ image = _myImage; } //网络图片 CGRect myRect; NSDictionary * dict = (NSDictionary *)[attrs objectForKey:@"dict"]; myRect.size.height =[[dict objectForKey:@"height"] floatValue]; myRect.size.width = [[dict objectForKey:@"width"]floatValue]; myRect.origin.x = runRect.origin.x; myRect.origin.y = origin.y; NSMutableArray * arr = [NSMutableArray array]; [arr addObject:[NSValue valueWithPointer:context]]; [arr addObject:image]; [arr addObject:NSStringFromCGRect(myRect)];// [self performSelectorOnMainThread:@selector(drawImage:) withObject:arr waitUntilDone:NO]; CGContextDrawImage(context, myRect, image.CGImage); } } } }}
-(void)downloadImageWithURL:(NSURL *)url{ __weak typeof(self) weakself = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData * data = [NSData dataWithContentsOfURL:url]; _myImage = [UIImage imageWithData:data]; NSLog(@"%@",@"下载完毕 设置图片"); if (_myImage) { NSLog(@"%@",@"sadsga"); dispatch_async(dispatch_get_main_queue(), ^{ [weakself setNeedsDisplay]; }); } });}
这里涉及到几个点,
1.网络图片需用本地图片占位 否则下载完毕绘图之后会出现位置不对的情况
2.setNeedsDisplay方法会直接通知view调用drawRect方法刷新。
setNeedsDisplay方法和setNeedsLayout后期会讲到。
执行结果:
0 0
- CoreText使用(2)图文混排
- coreText图文混排
- coretext 图文混排
- CoreText图文混排
- 使用CoreText实现图文混排
- CoreText(七):图文混排
- CoreText.framework --- 图文混排
- iOS coreText 图文混排
- CoreText实现图文混排
- CoreText实现图文混排
- CoreText实现图文混排
- IOS CoreText --- 图文混排
- IOS CoreText --- 图文混排
- CoreText实现图文混排
- CoreText实现图文混排
- CoreText实现图文混排
- CoreText 实现图文混排
- CoreText 实现图文混排
- iOS开发之如何跳到系统设置里的WiFi界面
- ios 给textField每四位添加一个空格
- hadoop eclipse 开发环境搭建
- 数据迁移工具-SSIS和Spoon 区别简介 -从浅入深(1.控件的基本用法)
- Collection(List)
- CoreText使用(2)图文混排
- CHM打不开的解决方法
- 如何获取显卡的GPU占用率和显存占用情况
- xml 命名空间(Namespace)
- 详解PHP ob_start()函数的功能要点
- Java 多线程(七) 线程间的通信——wait及notify方法
- linux更改文件属性的三个命令(chmod,chgrp,chown)的使用
- (Error)CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temp
- sqlserver的最大连接数测试