Making UITextView’s size exactly fit its content on iOS7

Sometimes you might want to add a UITextView as a subview to your layout, give it a specific width, assign some textual content to it and then make the text view exactly so high that it won’t scroll.

Back in the good old days of iOS6 one would just set the Frame size to the ContentSize of the UITextView. Done. But this does not work any longer on iOS7.

On iOS7 the ContentSize property is only correct after ViewDidAppear() has been called. If you don’t want to defer your layouting until then, you will need to invest a bit of extra work to get things right. The key to success is the LayoutManager property introduced in iOS7.

You can force the layout manager to layout the content of the text. After that is done, the correct size can be calculated. Enough of the theory, bring on the code!

I created a small extension method which will adjust the height of a UITextView’s frame without altering its X and Y coordinates and width.

You use it by creating a text view, then set the required X, Y and width. It does not matter what value you provide for the height, so just use “1”.

After this, call the method below.

/// <summary>
/// Adjusts the height of a UITextField so that for a given content it does not need to be scrolled.
/// </summary>
/// <returns>the height</returns>
/// <param name="textView">Text view. The Frame of the text view will be altered. The X, Y coordinates and the width remain unchanged.</param>
public static float AdjustToFittingHeight(this UITextView textView)
{
if (textView == null) {
return 0;
}

// Using simply ContentSize does not work on iOS7. The dimensions are calculated lazily.
// Enforce the layout of the text container to get correct measurements.
textView.LayoutManager.EnsureLayoutForTextContainer (textView.TextContainer);

// Get container size from the layout manager.
var containerSize = textView.LayoutManager.GetUsedRectForTextContainer (textView.TextContainer).Size;

// Take insets into consideration.
float height = (float)Math.Ceiling(containerSize.Height + textView.TextContainerInset.Top + textView.TextContainerInset.Bottom);

// Adjust frame but only alter height.
textView.Frame = new RectangleF (textView.Frame.X, textView.Frame.Y, textView.Frame.Width, height);

// Return the height for convenient access.
return height;
}
Advertisements