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):
Any ideas on how to render the text view with a proportional height? Thanks a lot!
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With