UITextView with dynamically height - ios

I have a textView which insert different texts with different lengths, some are short and others are long.. The UITextView is subviews of a scrollView. How can I dynamically set the height of UITextView according to the length of the entered text?
This code in ViewDidLoad doesn't work:
self.textView.contentSize = [self.textView.text sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(100, self.textView.contentSize.height) lineBreakMode:UIViewAutoresizingFlexibleHeight];

This does not work because your contraint is the current contentSize of the TextView. You should put the maximum size that you want.
For example your code could be like this :
#define kMaxHeight 100.f
self.textView.contentSize = [self.textView.text sizeWithFont:[UIFont systemFontOfSize:14]
constrainedToSize:CGSizeMake(100, kMaxHeight)
lineBreakMode:UIViewAutoresizingFlexibleHeight];
Hope this helps

As UITextView is a subclass of UIScrollView , so may be this will be helpful:
UITextView *textView = [UITextView new];
textView.text = #"Your texts ......";
CGSize contentSize = textView.contentSize ;
CGRect frame = textView.frame ;
frame.size.height = contentSize.height ;
textView.frame = frame ;

Below coding is working.Please try it
// leave the width at 300 otherwise the height wont measure correctly
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(10.0f, 0.0f, 300.0f, 100.0f)];
// add text to the UITextView first so we know what size to make it
textView.text = [_dictSelected objectForKey:#"body"];
// get the size of the UITextView based on what it would be with the text
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;

Calculate string size that fits in UITextView:
[yourString sizeWithFont:yourtxtView.font
constrainedToSize:CGSizeMake(yourtxtView.frame.size.width,1000)
lineBreakMode:UILineBreakModeWordWrap];
Change frame of UITextView
yourtxtView.frame = CGRectMake(yourtxtView.frame.origin.x,yourtxtView.frame.origin.y,yourtxtView.frame.size.width,yourtxtView.frame.size.height+20);

Related

How to handle Storyboard ViewControllers in iOS?

I have added 3 Views in ViewController, if 2nd/middle view has no text or it has one line text, the height of the middle view should be 30 and last view should move up at run time.
ADD THIS TO YOUR CODE:
CGSize maximumLabelSize = CGSizeMake(296, FLT_MAX);
CGSize expectedLabelSize = [yourString sizeWithFont:yourLabel.font constrainedToSize:maximumLabelSize lineBreakMode:yourLabel.lineBreakMode];
CGRect newFrame = yourLabel.frame;
newFrame.size.height = expectedLabelSize.height;
yourLabel.frame = newFrame;
ADD this CODE
[yourlabel sizeToFit ];
or
[yourView sizeToFit];

How to calculate TextView height base on text

I am using the code below for calculate the height of text, then set this height for UILabel and UITextView
CGSize targetSize = CGSizeMake(300, CGFLOAT_MAX);
NSString *message = #"The Internet connection appears to be offline.";
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGSize boundingBox = [message boundingRectWithSize:targetSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:FontOpenSanWithSize(14)}
context:context].size;
CGSize size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height));
// it will return size:width = 299 and size height 20
// => if I use this height and set for UILabel, it can display full content
// => if I use this height and set for UITextView, it can not display full content
It's work perfect for UILabel but for UITextView sometime it calculate wrong.
I think the problem happened because the padding (left, right) of UITextView is bigger than UILabel.
So how can I calculate the correct size of text for display in UITextView. Any help or suggestion would be great appreciated.
Like the description image below
With the same size (300), same font, same text but the UITextView display in 2 lines, but UILabel in 1 lines.
And my code for calculate height return 20, it not enough for display in 2 lines, so the UITextViewcan not display full content
The reason why I need to calculate the height of UITextView base on text because my UITextView is in a popup.
And the popup height will depend on the TextView height
There are two things you can try:
Set textView.textContainerInset = UIEdgeInsetsZero
Set textView.textContainer.lineFragmentPadding = 0
With these operations you can get rid of all the padding in the textView and when its width matches with the label's one the heights are also the same.
Here's a sample code you can place in an empty viewController and test it yourself:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSString *text = #"The internet connection appears to be offline.";
CGFloat width = 100.f;
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 20, width, 300)];
textView.font = [UIFont fontWithName:#"AvenirNext-Regular" size:12.f];
textView.text = text;
[self.view addSubview:textView];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20 + width, 20, width, 300)];
label.numberOfLines = 0;
label.font = [UIFont fontWithName:#"AvenirNext-Regular" size:12.f];
label.text = text;
[self.view addSubview:label];
// Getting rid of textView's padding
textView.textContainerInset = UIEdgeInsetsZero;
textView.textContainer.lineFragmentPadding = 0;
// Setting height of textView to its contentSize.height
CGRect textViewFrame = textView.frame;
textViewFrame.size = textView.contentSize;
textView.frame = textViewFrame;
// Setting height of label accorting to it contents and width
CGRect labelFrame = label.frame;
labelFrame.size = [label sizeThatFits:CGSizeMake(width, HUGE_VALF)];
labelFrame.size.width = width;
label.frame = labelFrame;
NSLog(#"Label bounds: %#", NSStringFromCGRect(label.bounds));
NSLog(#"TextView bounds: %#", NSStringFromCGRect(textView.bounds));
// Visualizing final effect with borders
textView.layer.borderColor = [UIColor redColor].CGColor;
textView.layer.borderWidth = 1.f;
label.layer.borderColor = [UIColor greenColor].CGColor;
label.layer.borderWidth = 1.f;
}
Console output:
2016-09-01 14:29:06.118 stack39268477[943:243243] Label bounds: {{0, 0}, {100, 66}}
2016-09-01 14:29:06.119 stack39268477[943:243243] TextView bounds: {{0, 0}, {100, 66}}
You don't need to calculate Height of UITextview based on text.
Just change frame and set height like this:
textview.size.height = textview.contentSize.height;
This is easy solution. I hope this helps you.
This calculates the size of any string, whether or not you put them in a text view.
let frame = NSString(string: yourText).boundingRect(
with: CGSize(width: yourDesiredWidth, height: .infinity),
options: [.usesFontLeading, .usesLineFragmentOrigin],
attributes: [.font : yourFont],
context: nil)
let height = frame.size.height
Most of the answers here are hints into the right direction :-)
So, just to sum it all up...
UITextView uses a NSTextContainer (inside a private API _UITextContainerView) to do the real layout work.
This NSTextContainer(View) may have insets to the surrounding UITextView, which are set by UITextView's textContainerInset property.
The defaults for this insets seem to be:
top: 8
left: 0
bottom: 8
right: 0
The NSTextContainer itself may have additional left and right insets for the text itself. These insets are set in NSTextContainer's lineFragmentPadding property.
The default for this is 5.0.
As a result, when calculating the optimum frame size for a UITextView based on the boundingRect for some text inside that UITextView, we have to take all these insets into account:
CGSize reservedSpace = CGSizeMake((textView.textContainerInset.left + (2.0 * textView.textContainer.lineFragmentPadding) + textView.textContainerInset.right),
(textView.textContainerInset.top + textView.textContainerInset.bottom));
CGSize targetSize = CGSizeMake((300.0 - reservedSpace.width), CGFLOAT_MAX);
NSString* message = #"The Internet connection appears to be offline.";
NSStringDrawingContext* context = [[NSStringDrawingContext alloc] init];
CGSize boundingBox = [message boundingRectWithSize:targetSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:FontOpenSanWithSize(14)}
context:context].size;
CGSize size = CGSizeMake(ceil(boundingBox.width),
(ceil(boundingBox.height) + reservedSpace.height));
Good luck :-)
Swift 5
A classic hack I've used to do this is create a function that takes the String as a parameter. Within the function it generates a label with the width required, infinite number of lines, and a height of "too much". Then apply sizeToFit() on the label and return the height of the frame.
func calculatedHeight(for text: String, width: CGFloat) -> CGFloat {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: width,
height: .greatestFiniteMagnitude))
label.numberOfLines = 0
label.text = text
label.sizeToFit()
return label.frame.height
}
The returned height can be applied to a UITextField height anchor. Though I do recommend calculating the width dynamically based on screen size, but that's up to you.
self.textView.textContainerInset = UIEdgeInsets.zero
self.textView.textContainer.lineFragmentPadding = 0
In storyboard or xib mark textview height >=0.
If you are using text view with table view.
Calculate cell height according to content, textview will adjust it's space.

Why is so much extra space being added to my UILabel when I try to change height to fit text?

I have no idea why the height of my UILabel is expanding to such a great height. It leaves the text of my UILabel in the centre. I don't want all of this extra space...
Unwanted extra space
Here is my code (I set the text before this point):
self.infoDescription.numberOfLines = 0;
[self.infoDescription sizeToFit];
self.infoDescription.frame = CGRectMake(20, self.infoAdultSize.frame.size.height+self.infoAdultSize.frame.origin.y+10, self.infoView.frame.size.width-40, self.infoDescription.frame.size.height);
Please help :( I just want the height of the UILabel to fit the text exactly.
First set the frame and then make size to fit of label.
**self.infoDescription.frame = CGRectMake(20, self.infoAdultSize.frame.size.height+self.infoAdultSize.frame.origin.y+10, self.infoView.frame.size.width-40, self.infoDescription.frame.size.height);
[self.infoDescription sizeToFit];**
Try this:
CGSize maximumSize = CGSizeMake(300, 9999);
NSString *myString = #"This is a long string which wraps";
UIFont *myFont = [UIFont fontWithName:#"Helvetica" size:14];
CGSize myStringSize = [myString sizeWithFont:myFont
constrainedToSize:maximumSize
lineBreakMode:self.myLabel.lineBreakMode];
(original source)
Please check this answer it works for me and it is exactly what you are looking for.
//Calculate the expected size based on the font and linebreak mode of your label
// FLT_MAX here simply means no constraint in height
CGSize maximumLabelSize = CGSizeMake(296, FLT_MAX);
CGSize expectedLabelSize = [yourString sizeWithFont:yourLabel.font constrainedToSize:maximumLabelSize lineBreakMode:yourLabel.lineBreakMode];
//adjust the label the the new height.
CGRect newFrame = yourLabel.frame;
newFrame.size.height = expectedLabelSize.height;
yourLabel.frame = newFrame;

How to adjust UITextView and scrollview dynamically based on data

In my project i have to adjust UItextview and UIScrollView dynamically based on data i am trying so much but perfect result is not coming please help me some one.
See my code for growing textview based on data and i don't know how to grow UIScrollView based on data please somebody help me.
- (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;
}
You can set the size of textview frame as
CGRect frame = textView.frame;
frame.size.height = textView.contentSize.height;
textView.frame=frame;
or you can try below code.
- (CGFloat)textViewHeightForAttributedText:(NSAttributedString *)text andWidth:(CGFloat)width
{
UITextView *textView = [[UITextView alloc] init];
[textView setAttributedText:text];
CGSize size = [textView sizeThatFits:CGSizeMake(width, FLT_MAX)];
return size.height;
}
or even You can try below code.
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
NSDictionary *attributes = #{ NSFontAttributeName: textView.font, NSParagraphStyleAttributeName : paragraphStyle };
CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributes
context:nil];

Get the exact size of UITextView with sizeWithAttribute

I have a UISlider that changes the font size of a UITextView. Before changing the font size, I would like to check if the height of my UITextView will be inferior to the height of its view container. The problem is that sizeToFit and sizeWithAttribute are returning different heights for the same font size.
To do that i'm trying to get the height of my UITextView with a custom fontSize, but i cannot figure out a way to do so, and don't understand why I don't get the same height when I do:
self.photoDescription.text = #"Test"
self.photoDescription.font = [self.photoDescription.font fontWithSize:18];
[self.photoDescription sizeToFit];
NSLog(#"real height %f", self.photoDescription.frame.size.height);
//getting : 37.5
and:
NSLog(#"calculated height %f", [self.photoDescription.text sizeWithAttributes:#{NSFontAttributeName:[self.photoDescription.font fontWithSize:18]}].height);
//getting: 20.97
same thing for:
CGRect textRect = [self.photoDescription.text boundingRectWithSize:CGSizeMake(320, 300)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:[self.photoDescription.font fontWithSize:18]}
context:nil];
CGSize size = textRect.size;
NSLog(#"height %f", size.height);
// getting : 20.97
Any thoughts on this?
I finally found an answer to my question with Jordan Montel Solution:
iOS7 UITextView contentsize.height alternative
I used his function to get the width :
- (CGFloat)textViewHeightForAttributedText:(NSAttributedString *)text andWidth:(CGFloat)width
{
UITextView *textView = [[UITextView alloc] init];
[textView setAttributedText:text];
CGSize size = [textView sizeThatFits:CGSizeMake(width, FLT_MAX)];
return size.height;
}

Resources