I'm working on rendering text in the center of a circular or oval shaped region. Ideally, I'd like to center the text vertically and horizontally, but have it flow naturally at the boundaries of the region.
I've found an approach using a UITextView
and NSTextContainer
with exclusion paths that does a good job of laying out the text at a given vertical offset, centered horizontally (code below). However, I'm not sure how to achieve vertical centering.
The approaches I've seen all suggest adjusting the contentInset
of the text view after the text has been laid out and the final height is known. (For example, this question) However, in the case of an irregularly shaped region, the height of the text after it's been laid out will depend on where in the region layout starts from.
An approach I've considered is to retry the layout process until a satisfactory layout is achieved. Has anyone had success with this kind of approach? One challenge here is that I haven't worked out how to determine whether all the text has been rendered within the view (i.e. whether there is enough space to lay out all the text) --- is there a way to query whether all content has been 'rendered' when using a UITextView?
Finally: this is just for displaying text --- there is no need to allow a user to edit the content of the view. Would CoreText
perhaps be a better approach in this case?
I'm fairly new to iOS development, so if there's anything outrageous I'm doing, that would also be helpful to know!
Thanks!
let boundingRect = CGRect(...)
let textView = UITextView(frame: boundingRect)
textView.editable = false
view.addSubview(textView)
let verticalInset:CGFloat = <some value>
let width = boundingRect.width
let height = boundingRect.height
let textBounds = CGSize(width: width, height:height - 2*verticalInset)
textView.bounds = textBounds
let exclusionRect = CGRect(x:0, y:-verticalInset, width:width, height:height)
let textRegion = UIBezierPath(ovalInRect: exclusionRect)
let exclusionPath = UIBezierPath(rect:exclusionRect)
exclusionPath.appendPath(textRegion.bezierPathByReversingPath())
textView.textContainer.exclusionPaths = [exclusionPath]
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .Center
let attributes = [NSParagraphStyleAttributeName: paragraphStyle]
let formattedContent = NSAttributedString(string: "....", attributes:attributes)
textView.attributedText(formattedContent)
Here's an image to help visualize the above, if helpful: