美文网首页
CoreText图文混排思路以及代码实现

CoreText图文混排思路以及代码实现

作者: LiuffSunny | 来源:发表于2019-08-12 16:09 被阅读0次

    图文混排

    CoreText实际上并没有相应API直接将一个图片转换为CTRun并进行绘制,它所能做的只是为图片预留相应的空白区域,而真正的绘制则是交由CoreGraphics完成。(像OSX就方便很多,直接将图片打包进NSTextAttachment即可,根本无须操心绘制的事情,所以基于这个想法,M80AttributedLabel的接口和实现也是使用了attachment这么个概念,图片或者UIView都是被当作文字段中的attachment。)

    在CoreText中提供了CTRunDelegate这么个Core Foundation类,顾名思义它可以对CTRun进行拓展:AttributedString某个段设置kCTRunDelegateAttributeName属性之后,CoreText使用它生成CTRun是通过当前Delegate的回调来获取自己的ascent,descent和width,而不是根据字体信息。这样就给我们留下了可操作的空间:用一个空白字符作为图片的占位符,设好Delegate,占好位置,然后用CoreGraphics进行图片的绘制。以下就是整个图文混排代码描述的过程:

        // 自定检查图片,并处理图片相关信息 -> 存放图片数据模型的数组
        self.imageArr = [[self.attributedString setImageWithImageSize:self.imageSize font:self.font] mutableCopy];
    
    
    /**
     * 绘制图片
     */
    - (void)drawImages
    {
        // 如果_frameRef不存在,直接退出
        if (!self.frameRef) return;
        
        // 移除以前的图片视图
        [self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            [obj removeFromSuperview];
        }];
        
        // 1.获取需要展示的行数
        // 1.1获取lineRef的数组
        CFArrayRef lines = CTFrameGetLines(self.frameRef);
        // 1.2获取lineRef的个数
        CFIndex lineCount = CFArrayGetCount(lines);
        // 1.3计算需要展示的行树
        NSUInteger numberOfLines = self.numberOfLines != 0 ? MIN(lineCount, self.numberOfLines) : lineCount;
        
        //  2.获取每一行的起始位置数组
        CGPoint lineOrigins[numberOfLines];
        CTFrameGetLineOrigins(self.frameRef, CFRangeMake(0, numberOfLines), lineOrigins);
        
        // 3.循环遍历每一组中是否包含link
        for (CFIndex idx = 0; idx < numberOfLines; idx ++) {
            // 3.1寻找图片占位符的准备工作
            // 3.1.1获取idx对应行的lineRef
            CTLineRef lineRef = CFArrayGetValueAtIndex(lines, idx);
            // 3.1.2获取当前lineRef中的runRef数组
            CFArrayRef runs = CTLineGetGlyphRuns(lineRef);
            // 3.1.3获取当前lineRef中的runRef的个数
            CFIndex runCount = CFArrayGetCount(runs);
            // 3.1.4获取每一行对应的位置
            CGPoint lineOrigin = lineOrigins[idx];
            
            // 3.2遍历lineRef中的runRef,查找图片占位符
            for (CFIndex idx = 0; idx < runCount; idx ++) {
                // 3.2.1获取lineRef中对应的RunRef
                CTRunRef runRef = CFArrayGetValueAtIndex(runs, idx);
                // 3.2.2获取对应runRef的属性字典
                NSDictionary *runAttributes = (NSDictionary *)CTRunGetAttributes(runRef);
                // 3.2.3获取对应runRef的CTRunDelegateRef
                CTRunDelegateRef delegate = (__bridge CTRunDelegateRef)[runAttributes valueForKey:(id)kCTRunDelegateAttributeName];
                // 3.2.3如果不存在,直接退出本次遍历
                // ->证明不是图片,因为我们只给图片设置了CTRunDelegateRef
                if (nil == delegate) continue;
                
                // ->证明图片在runRef里
                // 4.开始绘制图片
                // 4.1获取图片的数据模型
                ZYAttributedImage *imageData = (ZYAttributedImage *)CTRunDelegateGetRefCon(delegate);
                
                // 4.2获取需要展示图片的frame
                CGRect imageFrame = CTRunGetTypographicBoundsForImageRect(runRef, lineRef, lineOrigin, imageData);
                
                // 4.3添加图片
                if (imageData.imageType == SXTImageGIFTppe) {
                    // 初始化imageView
                    UIImageView *imageView = [UIImageView imageViewWithGIFName:imageData.imageName frame:imageFrame];
                    // 调整imageView的Y坐标
                    [imageView setY:self.height - imageView.height - imageView.y];
                    [self addSubview:imageView];
                }else{
                    // 添加图形上下文
                    CGContextRef context = UIGraphicsGetCurrentContext();
                    UIImage *image = [UIImage imageNamed:imageData.imageName];
                    // 绘制图片
                    CGContextDrawImage(context, imageFrame, image.CGImage);
                }
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:CoreText图文混排思路以及代码实现

          本文链接:https://www.haomeiwen.com/subject/fplujctx.html