Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find the number of characters that fits in a UITextView with constant width and height with a given string?

In my application I need to set Read more into the text view if text input is large.so my approach is to find the range of string that would fit in the text view and append See More to it.Is there any way to achieve it in Swift.The requirement is to emulate the read more option to show the complete text in detailed view on tap like facebook.

like image 953
Jacob Davis Cherussery Avatar asked Jan 22 '15 07:01

Jacob Davis Cherussery


2 Answers

The function you are looking for is CTFramesetterSuggestFrameSizeWithConstraints. Essentially, it allows you to find out the number of characters that fit in a certain frame. You can use that number to cut off your current text and insert a button.

I wrote an implementation of this function for a subclass of a UILabel:

- (NSInteger)numberOfCharactersThatFitLabel {

    // Create an 'CTFramesetterRef' from an attributed string
    CTFontRef fontRef = CTFontCreateWithName((CFStringRef)self.font.fontName, self.font.pointSize, NULL);
    NSDictionary *attributes = [NSDictionary dictionaryWithObject:(__bridge id)fontRef forKey:(id)kCTFontAttributeName];
    CFRelease(fontRef);
    NSAttributedString *attributedString  = [[NSAttributedString alloc] initWithString:self.text attributes:attributes];
    CTFramesetterRef frameSetterRef = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedString);

    // Get a suggested character count that would fit the attributed string
    CFRange characterFitRange;
    CTFramesetterSuggestFrameSizeWithConstraints(frameSetterRef, CFRangeMake(0,0), NULL, CGSizeMake(self.bounds.size.width, self.numberOfLines*self.font.lineHeight), &characterFitRange);
    CFRelease(frameSetterRef);
    return (NSInteger)characterFitRange.length;
}

Here's a bog post for the full implementation of cutting off random text to a specified number of lines and appending "view more" text to it.

like image 91
kgaidis Avatar answered Sep 22 '22 16:09

kgaidis


A rough swift translation of kgaidis's excellent answer.

extension UILabel {

    func numberOfCharactersThatFitLabel() -> Int {
        let fontRef = CTFontCreateWithName(self.font.fontName as CFStringRef, self.font.pointSize, nil)
        let attributes = NSDictionary(dictionary: [kCTFontAttributeName : fontRef])
        let attributeString = NSAttributedString(string: text!, attributes: attributes as? [String : AnyObject])
        let frameSetterRef = CTFramesetterCreateWithAttributedString(attributeString as CFAttributedStringRef)

        var characterFitRange:CFRange

        CTFramesetterSuggestFrameSizeWithConstraints(frameSetterRef, CFRangeMake(0, 0), nil, CGSizeMake(bounds.size.width, CGFloat(numberOfLines)*font.lineHeight), &characterFitRange)

        return characterFitRange.length
    }
}
like image 30
hatunike Avatar answered Sep 24 '22 16:09

hatunike