美文网首页今日任务iOS进阶指南iOS Developer
使用CoreGraphics框架画文本内容在view上实现富文本

使用CoreGraphics框架画文本内容在view上实现富文本

作者: lixuCoding | 来源:发表于2016-08-09 16:53 被阅读212次

    用CoreGraphics框架画文本的用户体验较UITextView的好。但是效率会比UITextView差,还有支持图片的功能设置大小时不是很好处理。

    下面看一下画出来的富文本效果图:

    screen


    集成代码如下:

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSString *text = @"[健身]我下载demo啊test[大哭]lms在https://github.com/SoftProgramLX?tab=repositories测试[微笑]选打11111我的github";
        
        LXRichTextView *view = [[LXRichTextView alloc] init];
        view.text = text;
        view.isUrl = YES;//设置为NO则不匹配链接。
        view.backgroundColor = [UIColor greenColor];
        view.font = [UIFont systemFontOfSize:18];
        view.delegage = self;
        view.urlDic = @{@"我的github": @"https://github.com/SoftProgramLX?tab=repositories", @"下载demo": @"https://github.com/SoftProgramLX/LXDrawTextView"};
        [self.view addSubview:view];
        
        view.frame = CGRectMake(20, 40, 300, [LXHelpClass calculateLabelighWithText:text withMaxSize:CGSizeMake(300, MAXFLOAT) withFont:18 withSpaceRH:0]);
    }
    
    - (void)richTextView:(LXRichTextView *)view touchBeginRun:(LXRichTextBaseRun *)run
    {
        NSLog(@"%@", run.originalText);
    }
    
    • view.urlDic属性的作用:设置文本中出现的这些文本当作超链接处理,将文本作为字典的key,相应的地址作为value。
    • richTextView: touchBeginRun:这是点击了链接的触发方法,链接的地址是run.originalText。

    核心代码如下:

    - (void)drawRect:(CGRect)rect
    {
        //解析文本
        _textAnalyzed = [self analyzeText:_text andIsUrl:self.isUrl];
        
        //要绘制的文本
        NSMutableAttributedString* attString = [[NSMutableAttributedString alloc] initWithString:self.textAnalyzed];
        
        NSMutableParagraphStyle * paragraphStyle0 = [[NSMutableParagraphStyle alloc] init];
        [paragraphStyle0 setLineBreakMode:NSLineBreakByCharWrapping];
        [attString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle0 range:NSMakeRange(0, attString.length)];
        
    //    CTParagraphStyleSetting lineBreakMode;
    //    CTLineBreakMode lineBreak = kCTLineBreakByCharWrapping; //换行模式
    //    lineBreakMode.spec = kCTParagraphStyleSpecifierLineBreakMode;
    //    lineBreakMode.value = &lineBreak;
    //    lineBreakMode.valueSize = sizeof(CTLineBreakMode);
    //    CTParagraphStyleSetting settings[] = {lineBreakMode};
    //    CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(settings, 1);   //第二个参数为settings的长度
    //    [attString addAttribute:(NSString *)kCTParagraphStyleAttributeName
    //                      value:(id)paragraphStyle
    //                      range:NSMakeRange(0, attString.length)];
        
        //设置字体
        CTFontRef aFont = CTFontCreateWithName((__bridge CFStringRef)self.font.fontName, self.font.pointSize, NULL);
        [attString addAttribute:(NSString*)kCTFontAttributeName value:(__bridge id)aFont range:NSMakeRange(0,attString.length)];
        CFRelease(aFont);
        
        //设置颜色
        [attString addAttribute:(NSString *)kCTForegroundColorAttributeName value:(id)self.textColor.CGColor range:NSMakeRange(0,attString.length)];
        
        //文本处理
        for (LXRichTextBaseRun *textRun in self.richTextRunsArray)
        {
            [textRun replaceTextWithAttributedString:attString];
        }
    
        //绘图上下文
        CGContextRef context = UIGraphicsGetCurrentContext();
        
        CTParagraphStyleSetting lineBreakMode;
        CTLineBreakMode lineBreak = kCTLineBreakByCharWrapping; //换行模式
        lineBreakMode.spec = kCTParagraphStyleSpecifierLineBreakMode;
        lineBreakMode.value = &lineBreak;
        lineBreakMode.valueSize = sizeof(CTLineBreakMode);
        CTParagraphStyleSetting settings[] = {lineBreakMode};
        CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(settings, 1);   //第二个参数为settings的长度
        [attString addAttribute:(NSString *)kCTParagraphStyleAttributeName
                          value:(id)paragraphStyle
                          range:NSMakeRange(0, attString.length)];
        
        //修正坐标系
        CGAffineTransform textTran = CGAffineTransformIdentity;
        textTran = CGAffineTransformMakeTranslation(0.0, self.bounds.size.height);
        textTran = CGAffineTransformScale(textTran, 1.0, -1.0);
        CGContextConcatCTM(context, textTran);
    
        //绘制
        int lineCount = 0;
        CFRange lineRange = CFRangeMake(0,0);
        CTTypesetterRef typeSetter = CTTypesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attString);
        float drawLineX = 0;
        float drawLineY = self.bounds.origin.y + self.bounds.size.height - self.font.ascender;
        BOOL drawFlag = YES;
        [self.richTextRunRectDic removeAllObjects];
        
        while(drawFlag)
        {
            CFIndex testLineLength = CTTypesetterSuggestLineBreak(typeSetter,lineRange.location,self.bounds.size.width);
    check:  lineRange = CFRangeMake(lineRange.location,testLineLength);
            CTLineRef line = CTTypesetterCreateLine(typeSetter,lineRange);
            CFArrayRef runs = CTLineGetGlyphRuns(line);
            
            //边界检查
            CTRunRef lastRun = CFArrayGetValueAtIndex(runs, CFArrayGetCount(runs) - 1);
            CGFloat lastRunAscent;
            CGFloat laseRunDescent;
            CGFloat lastRunWidth  = CTRunGetTypographicBounds(lastRun, CFRangeMake(0,0), &lastRunAscent, &laseRunDescent, NULL);
            CGFloat lastRunPointX = drawLineX + CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(lastRun).location, NULL);
            
            if ((lastRunWidth + lastRunPointX) > self.bounds.size.width)
            {
                if (testLineLength > 0) {
                    testLineLength--;
                    CFRelease(line);
                    goto check;
                }
                
                drawFlag = NO;
            }
            
            //绘制普通行元素
            drawLineX = CTLineGetPenOffsetForFlush(line,0,self.bounds.size.width);
            CGContextSetTextPosition(context,drawLineX,drawLineY);
            CTLineDraw(line,context);
            
            //绘制替换过的特殊文本单元
            for (int i = 0; i < CFArrayGetCount(runs); i++)
            {
                CTRunRef run = CFArrayGetValueAtIndex(runs, i);
                NSDictionary* attributes = (__bridge NSDictionary*)CTRunGetAttributes(run);
                LXRichTextBaseRun *textRun = [attributes objectForKey:@"TQRichTextAttribute"];
                if (textRun)
                {
                    CGFloat runAscent,runDescent;
                    CGFloat runWidth  = CTRunGetTypographicBounds(run, CFRangeMake(0,0), &runAscent, &runDescent, NULL);
                    CGFloat runHeight = runAscent + (-runDescent);
                    CGFloat runPointX = drawLineX + CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, NULL);
                    CGFloat runPointY = drawLineY - (-runDescent);
    
                    CGRect runRect = CGRectMake(runPointX, runPointY, runWidth, runHeight);
                    
                    BOOL isDraw = [textRun drawRunWithRect:runRect];
                    
                    if (textRun.isResponseTouch)
                    {
                        if (isDraw)
                        {
                            [self.richTextRunRectDic setObject:textRun forKey:[NSValue valueWithCGRect:runRect]];
                        }
                        else
                        {
                            runRect = CTRunGetImageBounds(run, context, CFRangeMake(0, 0));
                            runRect.origin.x = runPointX;
                            [self.richTextRunRectDic setObject:textRun forKey:[NSValue valueWithCGRect:runRect]];
                        }
                    }
                }
            }
    
            CFRelease(line);
            
            if(lineRange.location + lineRange.length >= attString.length)
            {
                drawFlag = NO;
            }
    
            lineCount++;
            drawLineY -= self.font.ascender + (- self.font.descender) + self.lineSpacing;
            lineRange.location += lineRange.length;
        }
        
        CFRelease(typeSetter);
    }
    



    源码请点击github地址下载。


    QQ:2239344645 我的github

    相关文章

      网友评论

      本文标题:使用CoreGraphics框架画文本内容在view上实现富文本

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