CoreText实现图文混排
来源:互联网 发布:淘宝售后退款不提醒 编辑:程序博客网 时间:2024/05/07 02:12
IOS CoreText.framework — 基本用法
http://blog.csdn.net/fengsh998/article/details/8691823
IOS CoreText.framework — 段落样子CTParagraphStyle
http://blog.csdn.net/fengsh998/article/details/8700627
IOS CoreText.framework — 行 CTLineRef
http://blog.csdn.net/fengsh998/article/details/8701738
IOS CoreText.framework — 图文混排
http://blog.csdn.net/fengsh998/article/details/8714497
学习完了上述四篇博文准备做一个使用CoreText实现的图文混排的案例
由于CoreText采用的是底层的绘制方法,所以案例的实现要放在draw方法中进行实现
创建一个自定义视图CommonDetailView继承自UIView
在CommonDetailView.m文件中重写- (void)drawRect:(CGRect)rect;
- (void)drawRect:(CGRect)rect的调用只有在使用到此类的实例时才会调用
比如
CommonDetailView *cv =[[CommonDetailView alloc] init];//此时drawRect并不会调用
只有当
[self.view addSubview:cv];//此时调用CommonDetailView的drawRect方法
这其实是视图的加载时的一种懒加载方式
下面开始重写drawRect方法
- (void)drawRect:(CGRect)rect { //得到绘图上下文对象(上下文是一种属性的有序序列,它们为驻留在环境内的对象定义环境。在对象的激活过程中创建上下文,对象被配置为要求某些自动服务,如同步、事务、实时激活、安全性等等) CGContextRef context = UIGraphicsGetCurrentContext(); //设置字形变换矩阵为CGAffineTransformIdentity,也就是说每一个字形都不做图形变换 // CGContextSetTextMatrix(context, CGAffineTransformIdentity); //CGAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d,CGFloat tx, CGFloat ty) //ad缩放,bc旋转,tx,ty位移 CGAffineTransform flipVertical = CGAffineTransformMake(1,0,0,-1,0,self.bounds.size.height); //将当前context的坐标系进行翻转(如果没有将坐标系进行翻转,则绘制结果会倒置) CGContextConcatCTM(context, flipVertical); //创建需要绘制的文本 //标题 NSString *str = @"第一段:由触控科技主办的《Cocos 2015开发者大会(春季)》将于4月2日正式召开。作为当前市场占有率最高的开源手游引擎,今年的cocos开发者大会吸引了大批媒体和从业者的关注。门票一经发售,即引发了抢购热潮。第二段:为了满足不同参会者的需求,此次官方贴心地设置了多种梯队门票,包括免费票、个人票、团体票及VIP众筹门票。据悉,目前距离大会仍有约两周的时间,门票销量已经超过一半,还没有购票的小伙伴们要抓紧时间啦!";//创建属性字符串NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]initWithString:str];//对此段文本使用的字体属性 UIFont *font = [UIFont fontWithName:nil size:kTitleFontSize]; CTFontRef fontRef = CTFontCreateWithName((CFStringRef)nil, font.pointSize, nil);//为属性文本添加字体属性 [attributedString addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)fontRef range:NSMakeRange(0, str.length)]; CFRelease(fontRef); //为图片设置CTRunDelegate,delegate决定留给图片的空间大小等信息 //所有的代理方法不能使用外部成员变量,只能使用本身的参数 CTRunDelegateCallbacks imageCallbacks; imageCallbacks.version = kCTRunDelegateCurrentVersion; imageCallbacks.dealloc = RunDelegateDeallocCallback; imageCallbacks.getAscent = RunDelegateGetAscentCallback; imageCallbacks.getDescent = RunDelegateGetDescentCallback; imageCallbacks.getWidth = RunDelegateGetWidthCallback; //创建CTRunDelegateRef UIImage *image = [UIImage imageWithData:[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://ss0.bdstatic.com/5a21bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png"]]]; CTRunDelegateRef runDelegate = CTRunDelegateCreate(&imageCallbacks, (__bridge void *)(image)); //创建需要绘制的图片的占位文本字符串 NSMutableAttributedString *imageAttributedString = [[NSMutableAttributedString alloc] initWithString:@" "];//空格用于给图片留位置 //为占位文本添加代理属性(即决定要绘制时的属性:如图片的宽高等),绘制时便会自动调用代理方法,为图片留出空间 //NSMakeRange(0, 1)表示从文本的0位置往后1个字符将会用图片进行替换 [imageAttributedString addAttribute:(NSString *)kCTRunDelegateAttributeName value:(__bridge id)runDelegate range:NSMakeRange(0, 1)]; //释放CTRunDelegateRef// CFRelease(runDelegate); //为占位文本添加属性(即决定要绘制时的属性) //这里添加的属性是要绘制的图片 NSString *imgName = [NSString stringWithFormat:@"https://ss0.bdstatic.com/5a21bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png"]; //在属性字符串0-1的位置添加属性,值为图片的地址 [imageAttributedString addAttribute:@"imageName" value:imgName range:NSMakeRange(0, 1)]; //将占位文本插入到全局要绘制的属性字符串的某个位置处(这里就添加到第二段文字前) NSRange range = [str rangeOfString:@"第二段"]; [attributedString insertAttributedString:imageAttributedString atIndex:NSMakeRange(0, rang.location)]; //设置段落格式 //换行模式 CTLineBreakMode lineBreak = kCTLineBreakByCharWrapping; CTParagraphStyleSetting lineBreakMode; lineBreakMode.spec = kCTParagraphStyleSpecifierLineBreakMode; lineBreakMode.value = &lineBreak; lineBreakMode.valueSize = sizeof(CTLineBreakMode); //首行缩进若干坐标点 CGFloat fristlineindent = 10.0f; CTParagraphStyleSetting fristline; fristline.spec = kCTParagraphStyleSpecifierFirstLineHeadIndent; fristline.value = &fristlineindent; fristline.valueSize = sizeof(float); //最大行高 CGFloat _linespace = 5.0f; CTParagraphStyleSetting lineSpaceSetting; lineSpaceSetting.spec = kCTParagraphStyleSpecifierLineSpacing; lineSpaceSetting.value = &_linespace; lineSpaceSetting.valueSize = sizeof(float); CTParagraphStyleSetting settings[] = { lineBreakMode, fristline, lineSpaceSetting, }; //段落格式属性组 CTParagraphStyleRef style = CTParagraphStyleCreate(settings, 3); //将段落格式属性组转成字典 NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(__bridge id)style forKey:(id)kCTParagraphStyleAttributeName ]; CFRelease(style); //全局绘制信息添加段落格式属性组 [attributedString addAttributes:attributes range:NSMakeRange(0, [attributedString length])]; //CTFramesetter是CTFrame对象工厂,而一个CTFrame就是一个段落,一个段落包含多个行CTLine,一行包括多个分割CTRun CTFramesetterRef ctFramesetter = CTFramesetterCreateWithAttributedString((CFMutableAttributedStringRef)attributedString); //创建图形绘制句柄(即绘制路径) CGMutablePathRef path = CGPathCreateMutable(); //绘制区域 CGRect bounds = CGRectMake(0, -10, 320, 500); //添加绘制区域到绘制句柄(之后通过上下文来进行绘制) CGPathAddRect(path, NULL, bounds); //从CTFramesetter工厂中生产CTFrame对象(分割段落)CFRangeMake表示范围 CTFrameRef ctFrame = CTFramesetterCreateFrame(ctFramesetter,CFRangeMake(0,str.length), path, NULL); //开始绘制(会回调代理方法,为图片留出区域) CTFrameDraw(ctFrame, context); //绘制图片======================================================================================= //得到所有绘制行 CFArrayRef lines = CTFrameGetLines(ctFrame); MyLog(@"总行数%ld",CFArrayGetCount(lines)); //CFArrayGetCount(lines):得到绘制的行数 CGPoint lineOrigins[CFArrayGetCount(lines)]; //得到行原点 也就是ctFrame从哪开始, CTFrameGetLineOrigins(ctFrame, CFRangeMake(0, 0), lineOrigins); //循环遍历所有绘制行 for (int i = 0; i < CFArrayGetCount(lines); i++) { CTLineRef line = CFArrayGetValueAtIndex(lines, i); CGFloat lineAscent;//原点上行线高度 CGFloat lineDescent;//原点下行线高度 CGFloat lineLeading;//行距 //CTLineGetTypographicBounds:计算排版的属性赋值 CTLineGetTypographicBounds(line, &lineAscent, &lineDescent, &lineLeading);//PS:此时行的高度 = lineAscent + lineDescent + lineLeading; // MyLog(@"行=%d,lineAscent=%f,lineDescent=%f",i,lineAscent,lineDescent); //获取每一行的CTRun数组(CTRun的分割规则是,根据标点符号或者图片进行分割) CFArrayRef runs = CTLineGetGlyphRuns(line); for (int j = 0; j < CFArrayGetCount(runs); j++) { CGFloat runAscent; CGFloat runDescent; //获取CTRun原点 CGPoint lineOrigin = lineOrigins[i]; //获取CTRun CTRunRef run = CFArrayGetValueAtIndex(runs, j); //得到给CTRun设置的属性 NSDictionary* attributes = (NSDictionary *)CTRunGetAttributes(run); //此处runRect保存的是图片所在行的rect CGRect runRect; //CTLineGetTypographicBounds计算排版的属性赋值 runRect.size.width = CTRunGetTypographicBounds(run, CFRangeMake(0,0), &runAscent, &runDescent, NULL); 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]; NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@",imageName]]; //下载图片 UIImage *image = [UIImage imageWithData:[[NSData alloc] initWithContentsOfURL:url]]; if (image) { //设置绘制的图片区域 CGRect imageDrawRect; imageDrawRect.size.width = 320 * 0.2; imageDrawRect.size.height = 320 * 0.2; // imageDrawRect.origin.x = runRect.origin.x + lineOrigin.x - 24; imageDrawRect.origin.x = (320 - 320 * 0.2) / 2; imageDrawRect.origin.y = runRect.origin.y;//绘制图片 CGContextDrawImage(context, imageDrawRect, image.CGImage); } } } } CFRelease(ctFramesetter); CFRelease(path); CFRelease(ctFrame);}#pragma mark -为要绘制的图片留出位置void RunDelegateDeallocCallback( void* refCon ){}//控制留出区域的上行高度(一行的原点距离其最顶部的距离)CGFloat RunDelegateGetAscentCallback( void *refCon ){ return 320 * 0.2;}CGFloat RunDelegateGetDescentCallback(void *refCon){ return 10 * 2;}//控制留出区域的宽度CGFloat RunDelegateGetWidthCallback(void *refCon){ return 320 ;}
0 0
- CoreText实现图文混排
- CoreText实现图文混排
- CoreText实现图文混排
- CoreText实现图文混排
- CoreText实现图文混排
- CoreText实现图文混排
- CoreText 实现图文混排
- CoreText 实现图文混排
- 使用CoreText实现图文混排
- CoreText实现气泡图文混排
- CoreText实现图文混排和AlassetLibrary
- coreText图文混排
- coretext 图文混排
- CoreText图文混排
- CoreText.framework --- 图文混排
- iOS coreText 图文混排
- IOS CoreText --- 图文混排
- IOS CoreText --- 图文混排
- Word怎么能有效转换成PDF格式
- 黑马程序员--java基础--网络编程(UDP和TCP)
- 由于检索用户的本地应用程序数据路径时出错,导致无法生成 SQL Server 的用户实例。解决方案
- 机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理)
- file文件复制
- CoreText实现图文混排
- Doxygen简介
- Android开发教程--关于Adapter的The content of the adapter has changed问题分析
- Linux复习(六)
- 关于安卓visualizer的用法
- 信息系统开发中常用的需求获取方法和技术
- virtualbox无法创建64虚拟机的解决办法
- 使用MKL求解矩阵的行列式值与逆
- 如何搭建Eclipse+Maven环境