Search code examples
iphonecore-textnsattributedstring

iPhone: break the text into line for frame


I have a looong text and a UILabel with width 300 with wordwrap mode. I need do know how many lines will be if to set my text to this label...And the main thing is to get line where the world "hello" is. How to do that ? How to break text into lines for some frame with some width and get the array of this lines ? Thanks....


Solution

  • Well, to get the number of lines, all you have to do is take your string and use sizeWithFont:constrainedToSize: then divide the height by your label's UIFont's lineHeight property.

    As for getting individual lines, I'm not sure if there's a way to do this with Objective-C, so you might have to use Core Text.

    Create an NSAttributedString from your string.

    Set the font.

    Create a CTFrameSetter from the NSAttributedString

    Create the CTFrame

    Get a CFArrayRef of lines from CTFrame using CTFrameGetLines

    Enumerate through the array and find your word.

    If you use fast enumeration, then you'll need a counter to keep track of the line number.

    Example of the line breaking part:

    CTFontRef myFont = CTFontCreateWithName([font fontName], [font pointSize], NULL);
    NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:string];
    [attStr addAttribute:(NSString *)kCTFontAttributeName value:(id)myFont range:NSMakeRange(0, attStr.length)];
    
    
    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attStr);
    
    CGPathRef path = [[UIBezierPath bezierPathWithRect:textFrame] CGPathRef];
    CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
    
    NSArray *lines = (NSArray *)CTFrameGetLines(frame);
    

    You'll have to add the appropriate releases depending on whether you're using ARC or not.

    Note that the variable "font" is a UIFont. If you want to create a font, you don't have to use those fontName and pointSize methods.

    Also note: this is an array of CTLineRef objects. Use CTLineGetStringRange to get the CFRange of the entire line. Then use that to create a substring from your NSString to do your searching in.

    NSUInteger idx = 0;
    for (CTLineRef line in lines) {
        CFRange lineRange = CTLineGetStringRange(line);
        NSRange range = NSMakeRange(lineRange.location, lineRange.length);
    
        NSString *lineString = [string substringWithRange:range];
    
        NSRange searchResultRange = [lineString rangeOfString:@"hello"];
        if (searchResultRange.location != NSNotFound) {
            // MATCH!
            break;
        }
    
        idx++;
     }