iOS新手学习ios 知识点iOS常用

iOS 文字超出行数限制末尾添加高亮可点击字

2020-04-21  本文已影响0人  水煮杰尼龟

  先上效果图


custom1.png custom2.png

在做文字超出行数限制末尾添加高亮点击字的需求的时候,遇到的这么一个问题。

如果只是在末尾追加高亮点击字,直接用yytext 就可以了。
原本我也是直接用yytext处理掉。 yytext 效果如下:


yytext.png

好像完全满足,然而有一种情况,我们产品不想要这样。这段文字中间加了个换行,导致高亮字的那一行末尾是空的 的情况,yytext效果如下:


yytext2.png
而我们的产品要的是这种情况也显示在最后。我用yytext没试出来。所以没的办法,只有自己想法子,最后就采用了下面我用的方式。
分为3个点
//获取每行文字
- (NSArray *)getSeparatedLinesWithWidth:(CGFloat)width
{
    NSString *text = [self text];
    if (!text || text.length<1) {
        return 0;
    }
    UIFont *font = [self font];
    CTFontRef myFont = CTFontCreateWithName((__bridge CFStringRef)([font fontName]), [font pointSize], NULL);
    NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text];
    [attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)];
    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attStr);
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, CGRectMake(0,0,width,100000));
    CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
    NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame);
    NSMutableArray *linesArray = [[NSMutableArray alloc]init];
    for (id line in lines) {
        CTLineRef lineRef = (__bridge CTLineRef )line;
        CFRange lineRange = CTLineGetStringRange(lineRef);
        NSRange range = NSMakeRange(lineRange.location, lineRange.length);
        NSString *lineString = [text substringWithRange:range];
        [linesArray addObject:lineString];
        
    }
    return linesArray;
    
}

然后根据获取到的每一行文字,做行数限制及补空格,高亮字的处理。
最后通过NSLayoutManager, NSTextContainer and NSTextStorage来判断点击处是否在高亮字上,详细代码可看demo

- (BOOL)didTapAttributedTextInLabel:(UILabel *)label inRange:(NSRange)targetRange {
    NSParameterAssert(label != nil);
    
    CGSize labelSize = label.bounds.size;
    // create instances of NSLayoutManager, NSTextContainer and NSTextStorage
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:labelSize];
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:label.attributedText];

    // configure layoutManager and textStorage
    [layoutManager addTextContainer:textContainer];
    [textStorage addLayoutManager:layoutManager];

    // configure textContainer for the label
    textContainer.lineFragmentPadding = 0.0;
    textContainer.lineBreakMode = label.lineBreakMode;
    textContainer.maximumNumberOfLines = label.numberOfLines;

    // find the tapped character location and compare it to the specified range
    CGPoint locationOfTouchInLabel = [self locationInView:label];
    CGRect textBoundingBox = [layoutManager usedRectForTextContainer:textContainer];
    CGPoint textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
                                              (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
    CGPoint locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
                                                         locationOfTouchInLabel.y - textContainerOffset.y);
    NSInteger indexOfCharacter = [layoutManager characterIndexForPoint:locationOfTouchInTextContainer
                                                       inTextContainer:textContainer
                              fractionOfDistanceBetweenInsertionPoints:nil];

    if (NSLocationInRange(indexOfCharacter, targetRange)) {
        return YES;
    } else {
        return NO;
    }
    
}

也可以根据自己的业务需求,在代码里做一些改动,代码不多,简单易懂,不改动的可以直接拿我的分类用。

上一篇 下一篇

猜你喜欢

热点阅读