How do I size a UITextView to its content?
Solution 1
This works for both iOS 6.1 and iOS 7:
- (void)textViewDidChange:(UITextView *)textView
{
CGFloat fixedWidth = textView.frame.size.width;
CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
CGRect newFrame = textView.frame;
newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
textView.frame = newFrame;
}
Or in Swift (Works with Swift 4.1 in iOS 11)
let fixedWidth = textView.frame.size.width
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
textView.frame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
If you want support for iOS 6.1 then you should also:
textview.scrollEnabled = NO;
Solution 2
This no longer works on iOS 7 or above
There is actually a very easy way to do resizing of the UITextView
to its correct height of the content. It can be done using the UITextView
contentSize
.
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;
One thing to note is that the correct contentSize
is only available after the UITextView
has been added to the view with addSubview
. Prior to that it is equal to frame.size
This will not work if auto layout is ON. With auto layout, the general approach is to use the sizeThatFits
method and update the constant
value on a height constraint.
CGSize sizeThatShouldFitTheContent = [_textView sizeThatFits:_textView.frame.size];
heightConstraint.constant = sizeThatShouldFitTheContent.height;
heightConstraint
is a layout constraint that you typically setup via a IBOutlet by linking the property to the height constraint created in a storyboard.
Just to add to this amazing answer, 2014, if you:
[self.textView sizeToFit];
there is a difference in behaviour with the iPhone6+ only:
With the 6+ only (not the 5s or 6) it does add "one more blank line" to the UITextView. The "RL solution" fixes this perfectly:
CGRect _f = self.mainPostText.frame;
_f.size.height = self.mainPostText.contentSize.height;
self.mainPostText.frame = _f;
It fixes the "extra line" problem on 6+.
Solution 3
Update
The key thing you need to do is turn off scrolling in your UITextView.
myTextView.scrollEnabled = @NO
Original Answer
To make a dynamically sizing UITextView
inside a UITableViewCell
, I found the following combination works in Xcode 6 with the iOS 8 SDK:
Add a
UITextView
to aUITableViewCell
and constrain it to the sidesSet the
UITextView
'sscrollEnabled
property toNO
. With scrolling enabled, the frame of theUITextView
is independent of its content size, but with scrolling disabled, there is a relationship between the two.If your table is using the original default row height of 44 then it will automatically calculate row heights, but if you changed the default row height to something else, you may need to manually switch on auto-calculation of row heights in
viewDidLoad
:tableView.estimatedRowHeight = 150; tableView.rowHeight = UITableViewAutomaticDimension;
For read-only dynamically sizing UITextView
s, that’s it. If you’re allowing users to edit the text in your UITextView
, you also need to:
Implement the
textViewDidChange:
method of theUITextViewDelegate
protocol, and tell thetableView
to repaint itself every time the text is edited:- (void)textViewDidChange:(UITextView *)textView; { [tableView beginUpdates]; [tableView endUpdates]; }
And don’t forget to set the
UITextView
delegate somewhere, either inStoryboard
or intableView:cellForRowAtIndexPath:
Solution 4
Very easy working solution using code and storyboard both.
By Code
textView.scrollEnabled = false
By Storyboard
Uncheck the Scrolling Enable
No need to do anything apart of this.
Solution 5
Swift :
textView.sizeToFit()
drewh
A shark on whiskey is mighty risky; a shark on beer is a beer engineer!
Updated on August 09, 2021Comments
-
drewh almost 3 years
Is there a good way to adjust the size of a
UITextView
to conform to its content? Say for instance I have aUITextView
that contains one line of text:"Hello world"
I then add another line of text:
"Goodbye world"
Is there a good way in Cocoa Touch to get the
rect
that will hold all of the lines in the text view so that I can adjust the parent view accordingly?As another example, look at the notes' field for events in the Calendar application - note how the cell (and the
UITextView
it contains) expands to hold all lines of text in the notes' string. -
Kevlar over 14 yearsThat gets the size as if it would draw the text on a UILabel. If you set that size to the uitextview's frame then you will still have some scrolling necessary in it.
-
leviathan almost 14 yearsThis doesn't work! It causes an error: "lvalue required as left operand of assignment"
-
Lukasz over 13 yearsYou saved my day. I was struggling with selfCalculating class function extension forgetting about this. Thank You.
-
R. Dewi over 13 years@Ronnie, thank you for your code, i've use your code, but when my textview content reach 2000 line, this code made my app getting slow, can you tell me why??
-
Admin about 13 yearsHere the '5' in y - coordinate of UILabel is the gap that I want between textView and Label.
-
Yogesh about 13 years@Ronnie , where should we write this code. I would like to display one line of frame initially and as the user types in the frame should increase to accomodate the text without scrolling up.
-
Hot Licks almost 13 yearsCuriouser: When I reduce the text, so that contentSize is only 79 tall, adding 100 I get only 1 line displayed. I have to add 200 -- set UITextView height to 279 -- to get the 3 lines to display.
-
Hot Licks almost 13 yearsAha! I was setting text view height and then adjusting the height of the containing view. Apparently when I did that the text view height was being adjusted. Setting the containing view height first makes things work as expected (or, better, hoped for).
-
Rodrigo over 12 yearsUsing [_textView sizeToFit] refreshes the contentSize property, removing the requirement to add it to the scrollView beforehand.
-
Maciej Swic over 11 yearsYou can also add frame.size.height += (_textView.contentInset.top + _textView.contentInset.bottom); If you have changed the contentInset to avoid the blank frame around the text.
-
jweyrich about 11 yearsYou can only assign to
textView.frame
. -
Bo. about 11 years_textView.scrollEnabled = NO; is also needed. Otherwise, I ended with a shifted content after a newline.
-
Adam Carter about 11 yearsThis is so obvious now you said it, I was trying to calculate a height with the
sizeWithFont:forWidth:lineBreakMode
, thanks! -
Xander Dunn about 11 yearsThis is a great solution, but it doesn't work when using autolayout. Do you have any ideas on accomplishing this with autolayout turned on?
-
phatmann almost 11 yearsIf using autolayout, call
layoutIfNeeded
on the superview. Then you can grab the height fromcontentSize
. -
Stian Høiland over 10 yearsWhere can I read more about this? I'm totally lost as to the seemingly new behaviour in iOS 7 regarding this.
-
Henrik Erlandsson over 10 yearsIf you have made it work on iOS 7, please help in this question: stackoverflow.com/questions/19049532/…
-
Henrik Erlandsson over 10 yearsIt's about resizing the outer container though. That behavior has changed in iOS 7. I show in the linked question where to add sizeToFit and layoutIfNeeded.
-
Tchelow over 10 yearsWhat's the meaning of the variable CGSize size?
-
giorashc over 10 years@HenrikErlandsson your comment saved me a lot of work right now :)
-
phatmann over 10 yearsI removed size, it was not supposed to be there.
-
Alex over 10 yearsTested on iOS 7 to resize an UITextView into an UITableViewCell. Works really great. This is the only answer that finally worked for me. Thanks!
-
Brian over 10 yearsI needed the
textview.scrollEnabled = NO;
to prevent the text from getting cut off even in iOS 7. -
michaelsnowden almost 10 yearssizetofit saves the day
-
eonil over 9 yearsI recommend to use
CGFLOAT_MAX
macro instead ofMAXFLOAT
. Proper on both of 32/64 bit platforms. -
scientiffic over 9 yearsthis worked for me, but then when I try to scroll the parent view to the textView when the user goes to edit it, the origin is off...
-
rob mayoff over 9 yearsUse
CGFLOAT_MAX
, notFLT_MAX
. -
Scooter over 9 yearsI wish I could give you more than one up vote for this awesome solution!!
-
user3344977 over 9 yearsHad to disable autolayout for my nib file for this to work properly, otherwise the first and second characters of a new line distorted the text view's size.
-
fnc12 over 9 yearsAlso you can use INFINITY instead of CGFLOAT_MAX and MAXFLOAT. It looks more funny
-
Logic about 9 yearsperfect result in iOS 8.1
-
eremzeit about 9 yearsThe question is really language agnostic. Is it really necessary to go back and write swift ports for all answers on UIKit related questions? Seems like that makes for a noisy conversation.
-
Fareed Alnamrouti about 9 yearsthe problem that most of these questions has no specific programming language so you will find it in google even if you search for swift language
-
smmelzer about 9 yearsBest answer for me. Worked perfectly and UITableViewAutomaticDimension was added in iOS 5 so it is backwards-compatible.
-
Massmaker almost 9 yearsSorry, what does it mean:
let attribute = [NSFontAttributeName: textView.text.font!]
Is this really Swift code without errors?) Did you meanlet attribute = [NSFontAttributeName: textView.font!]
-
Antzi almost 9 yearsThis kind of answers are discouraged. You should post the relevant code here.
-
ajay_nasa over 8 yearsThe one who face little fluctuation before entering in next line add this ` NSRange bottom = NSMakeRange(textView.text.length -1, 1); [textView scrollRangeToVisible:bottom];`
-
Fateh Khalsa over 8 yearsWorked great!! NOTE for using Autolayout: I had to set top/bottom space to superview constraints first for this to work.
-
SimonTheDiver over 8 yearsDidn't quite work for me . The textViewDidChange method cause my tableview to bounce every time i typed a character. What I suggest is that instead of using that method , in the tableView : cellForRowAtIndexPath method, for the row with the textview on it, if you are in a read only mode set .scrollEnabled to NO, and if you are in an editing view set scroll enabled to YES. This way when just displaying it will always show the full text and when editing it will start with the full text and as you add further text will remain the same size with the earlier text scrolling off the top
-
SimonTheDiver over 8 yearsfurthermore I added a >= height constraint to the textview as an empty textfield had no height and couldn't be tapped on to start editing.
-
Christopher Pickslay over 8 yearsExcellent solution. For me, the
tableView.rowHeight = UITableViewAutomaticDimension
was unnecessary. -
Tomasz Onyszko about 8 yearsIn addition, I found that I needed to set scrolling enabled to false for this to work.
textView.scrollEnabled = false
-
nekonari about 8 yearsWhy are there two separate calls to sizeThatFits(...) in the Swift version? What's the first line for?
-
zztop almost 8 yearsThis does not work for me in 2016. Possibly out of date. The height of the content is always the frame height even when I added the addSubView
-
Daniel Kuta almost 8 yearsYou should remember to call textView.layoutIfNeeded() after textView.sizeToFit()
-
Daniel Kuta almost 8 yearsIf someone have a problem with resizing, put this code above to override func layoutSubviews() method.
-
pnavk almost 8 yearsThis answer is correct. In StoryBoard you have the TextView AutoSize just like a UILabel. All we need to do is set scrollEnabled=false.
-
Francisco Romero over 7 years@tmarkiewicz It works when the text fits on the screen of your device but it will be a problem when your text is bigger than the space that there is on the screen. You will not be able to scroll it to see the rest of the text.
-
jbll over 7 yearsThis works great. Was confused for a few minutes because I still had a height autolayout constraint set in IB for the text view, but after removing it everything is good.
-
Prashant Ghimire over 7 yearsthere is bug in this method in ios 9.the size of textview get to normal height when selecting text from text view
-
Eric Conner over 7 yearsThank you again Brett Donald! I forgot how to do this and found your answer once again over 1 year later 😀.
-
thibaut noah over 7 yearsPadding was the key for me
-
Brett Donald over 7 yearsFor anyone who comes across this answer in future, the main thing you need to know is simply UITextView.scrollEnabled = @NO
-
Derek over 7 yearsJust remember to add this into viewDidLayoutSubviews rather than viewWillAppear
-
Fattie about 7 yearsthat's a FANTASTIC nickname!
-
Will Larche about 7 yearsSetting the constant needs to be followed by [textView layoutIfNeeded]; in the animation block. (Autolayout animations do it like that.)
-
Dan Rosenstark about 7 yearsEssentially, this is correct: if you are using Autolayout constraints and shut off scrolling, the whole thing works.
-
Mansuu.... over 6 yearsdelegate method is not getting called @Peter Stajger
-
Wayne over 6 yearsWhen textview.scrollEnabled = NO; My cursor is not visible, after typing first character it becomes visible. When scrolling is enabled, when text is entered, the top text is scrolled up too much (over scrolling), after the first character is entered the scrolling fixes itself. So leaving scrolling enabled and using this line fixes it for me: NSRange bottom = NSMakeRange(textView.text.length -1, 1); [textView scrollRangeToVisible:bottom]; As aiay_nasa has posted.
-
Stefanija about 6 yearsIt causes the screen to bounce every time on update as @SimonTheDiver said
-
samir105 about 6 yearsThanks a lot. It was that simple, just disable scrolling in storyboard or code, it will be like UILabel with lines 0.
-
velval almost 6 yearsThis works great, just remember to to make sure you do not have height constraints set for the TextView in interface builder
-
Jake T. almost 6 years@Mansuu.... This isn't a guaranteed solution, as there are things that you can do to override the intrinsic content size, and if you change the text after the view is laid out it won't update unless you set that up, too. But, those things remain true for setting numberOfLines = 0 on a textfield, too. If this doesn't work, you probably have other constraints that will implicitly set a height.
-
iOS Flow almost 6 yearsNote: So this answer is just to highlight that you don't have to use the CGFloat.greatestFiniteMagnitude if you're constraint to a certain width or height -> spaceAvailable in my case can be max the screen width - Spacings and other labels width or min the screen width it all depends on what I display...
-
Naresh over 5 yearsYour answer is acceptable, but if we add height constraint it's won't work.
-
Alok over 5 years@iOS if you are adding height constraint then make constraints priority lower otherwise it will not work.
-
Ben Smith over 5 yearsThis is the answer!!! No need for more complicated solutions!!! @FranciscoRomero Why not put the textview in a table cell or colleciton view cell then you can always scroll the table or colleciton view....
-
ArielSD about 5 yearsThe sizing is looking great in the UI debugger, but the text isn't wrapping - I put this in
initWithFrame
, could that be the problem? -
JLundell almost 5 yearsAlternatively set the textView's height constraint to the calculated height.
-
JLundell almost 5 yearsRe @DanielKuta's suggestion, note that layoutSubviews() is a UIView function, great if you're subclassing the textview or a parent. If you're doing this in a view controller, viewWillLayoutSubviews() is what you want.
-
PakitoV almost 4 yearsfor future reference. If you are using Autolayout go check Alok answer, that's all you should need, as simple as that.
-
pete almost 4 yearsI don't think this can override constraints. How to specify this initially in the storyboard constraint? I don't even have dynamic text; just static.
-
fumoboy007 over 3 yearsExplanation of why this works: stackoverflow.com/a/65861960/815742
-
Vyachaslav Gerchicov almost 3 yearswhat if your text view has exclusion paths and you can't just calculate size for rect? In other words what to do if text view shape is not rect?