IOS CoreText系列三:图文混排

3 篇文章 0 订阅

  1. #import <UIKit/UIKit.h>  
  2.   
  3. @interface HSCoreTextView : UIView  
  4.   
  5. @end  

.m文件

[objc]  view plain  copy
  1. #import "HSCoreTextView.h"  
  2. #import <CoreText/CoreText.h>  
  3.   
  4. @implementation HSCoreTextView  
  5.   
  6.   
  7. //图片回调函数  
  8. static CGFloat ascentCallBacks(voidvoid *ref)  
  9. {  
  10.     //__bridge既是C的结构体转换成OC对象时需要的一个修饰词  
  11.     return [[(__bridge NSDictionary *)ref valueForKey:@"height"] floatValue];  
  12. }  
  13.   
  14. static CGFloat descentCallBacks(voidvoid *ref)  
  15. {  
  16.     return 0;  
  17. }  
  18.   
  19. static CGFloat widthCallBacks(voidvoid *ref)  
  20. {  
  21.     return [[(__bridge NSDictionary *)ref valueForKey:@"width"] floatValue];  
  22. }  
  23.   
  24. - (void)drawRect:(CGRect)rect  
  25. {  
  26.     [super drawRect:rect];  
  27.       
  28.     //1.绘制上下文  
  29.     //1.1获取绘制上下文  
  30.     CGContextRef context = UIGraphicsGetCurrentContext();  
  31.     //1.2.coreText 起初是为OSX设计的,而OSX得坐标原点是左下角,y轴正方向朝上。iOS中坐标原点是左上角,y轴正方向向下。若不进行坐标转换,则文字从下开始,还是倒着的,因此需要设置以下属性  
  32.     设置字形的变换矩阵为不做图形变换  
  33.     CGContextSetTextMatrix(context, CGAffineTransformIdentity);  
  34.     //平移方法,将画布向上平移一个屏幕高  
  35.     CGContextTranslateCTM(context, 0self.bounds.size.height);  
  36.     //缩放方法,x轴缩放系数为1,则不变,y轴缩放系数为-1,则相当于以x轴为轴旋转180度  
  37.     CGContextScaleCTM(context, 1.0, -1.0);  
  38.       
  39.     //2.设置图片回调函数  
  40.     //2.1创建一个回调结构体,设置相关参数  
  41.     CTRunDelegateCallbacks callBacks;  
  42.     //memset将已开辟内存空间 callbacks 的首 n 个字节的值设为值 0, 相当于对CTRunDelegateCallbacks内存空间初始化  
  43.     memset(&callBacks, 0sizeof(CTRunDelegateCallbacks));  
  44.     //2.2设置回调版本,默认这个  
  45.     callBacks.version = kCTRunDelegateVersion1;  
  46.     //2.3设置图片顶部距离基线的距离  
  47.     callBacks.getAscent = ascentCallBacks;  
  48.     //2.4设置图片底部距离基线的距离  
  49.     callBacks.getDescent = descentCallBacks;  
  50.     //2.5设置图片宽度  
  51.     callBacks.getWidth = widthCallBacks;  
  52.     //2.6创建一个代理  
  53.     NSDictionary *dicPic = @{@"height":@"60",@"width":@"60"};  
  54.     CTRunDelegateRef delegate = CTRunDelegateCreate(&callBacks, (__bridge voidvoid * _Nullable)(dicPic));  
  55.   
  56.     //3.插入图片  
  57.     //创建空白字符  
  58.     unichar placeHolder = 0xFFFC;  
  59.     NSString *placeHolderStr = [NSString stringWithCharacters:&placeHolder length:1];  
  60.     NSMutableAttributedString *placeHolderMabString = [[NSMutableAttributedString alloc] initWithString:placeHolderStr];  
  61.     //给字符串中的范围中字符串设置代理  
  62.     CFAttributedStringSetAttribute((CFMutableAttributedStringRef)placeHolderMabString, CFRangeMake(01), kCTRunDelegateAttributeName, delegate);  
  63.       
  64.     //4.设置要显示的文字  
  65.     NSMutableAttributedString *mabString = [[NSMutableAttributedString alloc] initWithString:@"\n这里在测试图文混排,\n我是富文本"];  
  66.     [mabString insertAttributedString:placeHolderMabString atIndex:12];  
  67.       
  68.     //5.绘制文本  
  69.     //5.1.创建CTFramesetterRef  
  70.     CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)mabString);  
  71.       
  72.     //5.2.创建路径  
  73.     CGMutablePathRef path = CGPathCreateMutable();  
  74.     CGPathAddRect(path, NULLself.bounds);  
  75.       
  76.     //5.3.创建CTFrame  
  77.     NSInteger length = mabString.length;  
  78.     CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, length), path, NULL);  
  79.     CTFrameDraw(frame, context);  
  80.       
  81.     //6.添加图片并绘制  
  82.     UIImage *image = [UIImage imageNamed:@"icon-60"];  
  83.     CGRect imgFrm = [self calculateImageRectWithFrame:frame];  
  84.     CGContextDrawImage(context, imgFrm, image.CGImage);  
  85.       
  86.     //7.释放  
  87.     CFRelease(delegate);  
  88.     CFRelease(frame);  
  89.     CFRelease(path);  
  90.     CFRelease(framesetter);  
  91. }  
  92.   
  93. #pragma mark 计算图片Frame  
  94. - (CGRect)calculateImageRectWithFrame:(CTFrameRef)frame  
  95. {  
  96.     //根据frame获取需要绘制的线的数组  
  97.     NSArray *arrLines = (NSArray *)CTFrameGetLines(frame);  
  98.     NSInteger count = arrLines.count;  
  99.     CGPoint points[count];  
  100.     //获取起始点位置  
  101.     CTFrameGetLineOrigins(frame, CFRangeMake(00), points);  
  102.       
  103.     for (int i = 0; i < count; i ++) {  
  104.         CTLineRef line = (__bridge CTLineRef)(arrLines[i]);  
  105.         //CTRun 或者叫做 Glyph Run,是一组共享想相同attributes(属性)的字形的集合体  
  106.         NSArray *arrGlyphRun = (NSArray *)CTLineGetGlyphRuns(line);  
  107.         for (int j = 0; j < arrGlyphRun.count; j ++) {  
  108.             CTRunRef run = (__bridge CTRunRef)(arrGlyphRun[j]);  
  109.             //获取CTRun的属性  
  110.             NSDictionary *attributes = (NSDictionary *)CTRunGetAttributes(run);  
  111.             CTRunDelegateRef delegate = (__bridge CTRunDelegateRef)[attributes valueForKey:(id)kCTRunDelegateAttributeName];  
  112.             if (delegate == nil) {  
  113.                 continue;  
  114.             }  
  115.               
  116.             NSDictionary *dic = CTRunDelegateGetRefCon(delegate);  
  117.             if (![dic isKindOfClass:[NSDictionary class]]) {  
  118.                 continue;  
  119.             }  
  120.               
  121.             //获取一个起点  
  122.             CGPoint point = points[i];  
  123.             //获取上下距  
  124.             CGFloat ascent,desecent;  
  125.             //创建一个Frame  
  126.             CGRect boundsRun;  
  127.             boundsRun.size.width = CTRunGetTypographicBounds(run, CFRangeMake(00), &ascent, &desecent, NULL);  
  128.             boundsRun.size.height = ascent + desecent;  
  129.             //获取偏移量  
  130.             CGFloat xOffset = CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).locationNULL);  
  131.             boundsRun.origin.x = point.x + xOffset;  
  132.             boundsRun.origin.y = point.y - desecent;  
  133.             //获取绘制路径  
  134.             CGPathRef path = CTFrameGetPath(frame);  
  135.             //获取剪裁区域边框  
  136.             CGRect colRect = CGPathGetBoundingBox(path);  
  137.             CGRect imageBounds = CGRectOffset(boundsRun, colRect.origin.x, colRect.origin.y);  
  138.               
  139.             return imageBounds;  
  140.         }  
  141.     }  
  142.     return CGRectZero;  
  143. }  
  144.   
  145. @end  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值