美文网首页
创建label文字一对一点击事件

创建label文字一对一点击事件

作者: dl_wj15 | 来源:发表于2017-10-08 16:56 被阅读0次

由于项目需要对一个label里不同的文字点击响应不同的事件,在网上也没有找到比较好的demo,只好自己动手写一个,不到之处欢迎提出

本项目是给label添加分类方法,做到引用后项目里所有UILabel都能使用

具体实现代码

CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)self.attributedText);
    // 创建path
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, self.bounds);
    // 绘制frame range:传长度为0也可以。如果是0,会一直增加行数,直到text最后或者没有空间才停止。(numberOfLines)
    CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
    // 获得CTLine数组
    CFArrayRef lines = CTFrameGetLines(frame);
    NSInteger numberOfLines =CFArrayGetCount(lines);
    
    CGPoint lineOrigins[numberOfLines];
    // 获取每一行的origin range同上所述(numberOfLines)
    CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), lineOrigins);
    for (CFIndex lineIndex = 0; lineIndex < numberOfLines; lineIndex++) {
        // 获取行对应的origin
        CGPoint lineOrigin = lineOrigins[lineIndex];
        CTLineRef line = CFArrayGetValueAtIndex(lines, lineIndex);
        
        // 获取每行的 rect
        CGFloat ascent, descent, leading, width;
        width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
        
        // 获取富文本的行间距,默认0
        NSParagraphStyle *style = [self.attributedText attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:nil];
        CGFloat lineSpace = 0;
        if (style) {
            lineSpace = style.lineSpacing;
        }
        
        CGFloat lineH = ascent + fabs(descent) + leading;// 行高
        CGFloat textH = lineH * numberOfLines + lineSpace * (numberOfLines - 1);// 文本总高度
        CGFloat textY = (self.bounds.size.height - textH) * 0.5;// 文本开始的 y
        CGFloat lineY = textY + lineIndex * (lineH + lineSpace);// 当前行的开始 y
        CGFloat yMax = lineH + lineY; // 当前行最大 y
        
        if (point.y > yMax) {
            continue; // 点击的位置不在该行文本中
        }
        if (point.y >= lineY) {
            if (point.x >= lineOrigin.x && point.x <= lineOrigin.x + width) {
                // 相对位置
                CGPoint relativePoint = CGPointMake(point.x - lineOrigin.x, point.y - lineOrigin.y);
                // 获取当前点击的文本位置
                NSUInteger idx = CTLineGetStringIndexForPosition(line, relativePoint);
                idx--; // 文本起始位置1 range起始位置0
                [self.actionBlockDict enumerateKeysAndObjectsUsingBlock:^(AttributeActionBlock actionBlock, LWAttributeActionModel *model, BOOL * _Nonnull stop) {
                    if (NSLocationInRange(idx, model.range)) {
                        actionBlock(model.string);
                    }
                }];
            }
        }
    }

注意事项

  • label.userInteractionEnabled = YES
  • label.attributeText必须设置字体大小

源码:https://github.com/dlwj15/label-index.git

相关文章

网友评论

      本文标题:创建label文字一对一点击事件

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