Get number of lines in UITextView without contentSize.height

I'm creating an image to export in my iOS app. I am using UIGraphicsBeginImageContext to draw the elements of the image but I've been struggling drawing a UITextView in the image.

First I create a parent view for rendering:

var parentView : UIView = UIView(frame: CGRectMake(0, 0, 700, 700))

Then I programatically create the textView and add all the properties. I give it x=100 and y=100 to align the text in the image. Width = 500 is good to have a margin of 100px on each side:

var textView: UITextView = UITextView(frame: CGRectMake(100, 100, 500, 350))
textView.text = myText
textView.textContainerInset = UIEdgeInsetsMake(20, 20, 20, 20)
textView.backgroundColor = UIColor(red: 255, green: 255, blue: 255, alpha: 0.70)
textView.font = UIFont(name: "Helvetica Neue Light Italic", size: 35)

Then I render the textview in context by adding it as a subview to the parent view and then I get the image for export:

parentView.addSubview(textView)        
parentView.layer.renderInContext(UIGraphicsGetCurrentContext())    
var newIMG = UIGraphicsGetImageFromCurrentImageContext()

The problem is that the height is fixed to 350px, but sometimes the text is not long enough to use all that area. Ideally I would like to know how many lines will my text use, so I can give it a proportional height and not have a white unused area (see pic for example):

Info Any ideas on how to render the text view with a proportional height? Thanks a lot!


ANSWERS:


I found the perfect solution to this problem in Apple's Text Layout Programming Guide. The solution Apple provides is in Objective-C, so I tested and re-wrote it for Swift.

Both methods work great and return the exact number of lines that are being used in a UITextView, without funky math and 100% accurate every time.

Here is my extension to UITextView to add a numberOfLines() method:

extension UITextView {
    func numberOfLines() -> Int {
        let layoutManager = self.layoutManager
        let numberOfGlyphs = layoutManager.numberOfGlyphs
        var lineRange: NSRange = NSMakeRange(0, 1)
        var index = 0
        var numberOfLines = 0

        while index < numberOfGlyphs {
            layoutManager.lineFragmentRectForGlyphAtIndex(
                index, effectiveRange: &lineRange
            )
            index = NSMaxRange(lineRange)
            numberOfLines += 1
        }
        return numberOfLines
    }
}

Just call this directly on your UITextView like so: myTextView.numberOfLines() <- returns an Int


This extension is also easily converted to a method like so:

func numberOfLines(textView: UITextView) -> Int {
    let layoutManager = textView.layoutManager
    let numberOfGlyphs = layoutManager.numberOfGlyphs
    var lineRange: NSRange = NSMakeRange(0, 1)
    var index = 0
    var numberOfLines = 0

    while index < numberOfGlyphs {
        layoutManager.lineFragmentRectForGlyphAtIndex(index, effectiveRange: &lineRange)
        index = NSMaxRange(lineRange)
        numberOfLines += 1
    }
    return numberOfLines
}

Just call numberOfLines(myTextView) to retrieve an Int of the number of lines


I didn't find a way to get the number of lines, but I managed to remove all that white space using textView.sizeToFit(). It worked great, hopefully someone will find this useful!



 MORE:


 ? Get number of lines in UITextView without contentSize.height
 ? Get number of lines in UITextView without contentSize.height
 ? Background Image for UITextView
 ? iOS7 UITextView contentsize.height alternative
 ? Get number of lines UITextView without using "\n"?
 ? UITextView does not update its height after trying to change its height programmatically
 ? UITextView Font Size
 ? How to limit the number of lines in UITextView?
 ? Wrapping text in UITextView in Swift
 ? How to horizontally center UITextView content in iOS, but not using Align Center?