UITextView contentsize.height issue in iOS 7 - ios

I searched & spend so much time to resolve the issue of content size height, but it’s hard luck, nothing worked. Similar questions are available in stack & other forums also but i am not getting what is left, which is not allowing my textview to resolve this issue.
I have to place textView’s cursor & text at centre of it’s width & height. Now i use it-
UITextView *tv = object;
[tv setScrollEnabled:YES];
CGFloat height = [tv bounds].size.height;
CGFloat contentheight;
contentheight = [tv sizeThatFits:CGSizeMake(tv.frame.size.width, FLT_MAX)].height;
NSLog(#"iOS7; %f %f", height, contentheight);
// [tv sizeToFit];
CGFloat topCorrect = height - contentheight;
topCorrect = (topCorrect <0.0 ? 0.0 : topCorrect);
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
[tv setScrollEnabled:NO];
The Second Approach i used is-
#pragma mark- UITextView ContentHeight Messurment
- (CGFloat)measureHeightOfUITextView:(UITextView *)textView
{
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1)
{
// This is the code for iOS 7. contentSize no longer returns the correct value, so
// we have to calculate it.
//
// This is partly borrowed from HPGrowingTextView, but I've replaced the
// magic fudge factors with the calculated values (having worked out where
// they came from)
CGRect frame = textView.bounds;
// Take account of the padding added around the text.
UIEdgeInsets textContainerInsets = textView.textContainerInset;
UIEdgeInsets contentInsets = textView.contentInset;
CGFloat leftRightPadding = textContainerInsets.left + textContainerInsets.right + textView.textContainer.lineFragmentPadding * 2 + contentInsets.left + contentInsets.right;
CGFloat topBottomPadding = textContainerInsets.top + textContainerInsets.bottom + contentInsets.top + contentInsets.bottom;
frame.size.width -= leftRightPadding;
frame.size.height -= topBottomPadding;
NSString *textToMeasure = textView.text;
if ([textToMeasure hasSuffix:#"\n"])
{
textToMeasure = [NSString stringWithFormat:#"%#-", textView.text];
}
// NSString class method: boundingRectWithSize:options:attributes:context is
// available only on ios7.0 sdk.
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];
CGFloat measuredHeight = ceilf(CGRectGetHeight(size) + topBottomPadding);
return measuredHeight;
}
else
{
return textView.contentSize.height;
}
}
The response is coming like it-
After editing it, it's appearing like it-
Now, what else i can try to put textView's text on the centre of UITextView? Please update me.

Related

boundingRectWithSize not replicating UITextView

My requirement in a project is that the font size of the UITextView should decrease according the content of the UITextView. So i am trying to do estimate the size of the text using boundingRectWithSize.
The problem is that the font size I get is a bit too big and some part of the text does get clipped.
My Function :
-(BOOL)updateTextViewFontSizeForText:(NSString*)text{
float fontSize = self.maximumFontSizeInPoints;
self.font = [self.font fontWithSize:fontSize];
CGSize tallerSize ;
CGSize stringSize ;
do
{
if (fontSize <= self.minimumFontSizeInPoints) // it just won't fit
return NO;
fontSize -= 1.0;
self.font = [self.font fontWithSize:fontSize];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
NSDictionary *attributes = #{ NSFontAttributeName: self.font, NSParagraphStyleAttributeName : paragraphStyle };
tallerSize = CGSizeMake(self.frame.size.width,self.frame.size.height-16);// the 16 is given because uitextview adds some offset
stringSize = [text boundingRectWithSize:CGSizeMake(self.contentSize.width,CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
}while(stringSize.height >= tallerSize.height);
if ([self.onTextChangDelegate respondsToSelector:#selector(onTextChangDelegate)]) {
[self.onTextChangDelegate onTextChanged:text];
}
return YES;
}
I ran into the same issue when trying to do the same thing.
The issue is how UITextView run's its line-breaks compared to boundingRectWithSize. You can read more details here: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/TextLayout/Concepts/CalcTextLayout.html
But you can actually calculate the exact size! There are basically two properties of a UITextView that you'll need to take into account in order to get correct size estimates. The first is textContainer.lineFragmentPadding, the second is textContainerInset.
First, textContainer.lineFragmentPadding: You may have noticed that your sizing is generally always off by 10px, this is because the systems default value is 5px. When you're calculating your estimated size, you'll need to subtract this value from the size you're checking against and add it back when you have your final value.
Second, textContainerInset. This is a UIEdgeInset that you'll need to add back to your final calculated value to match the systems.
This is code based on how I solved the issue:
- (CGSize)sizeThatFits:(CGSize)size
CGFloat lineFragmentPaddings = self.textContainer.lineFragmentPadding * 2;
CGFloat horzPadding = self.textContainerInset.left + self.textContainerInset.right + lineFragmentPaddings;
CGFloat vertPadding = self.textContainerInset.top + self.textContainerInset.bottom;
size.width -= horzPadding;
CGRect boundingRect = [attributedText boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin context:nil];
size = boundingRect.size;
// I found through debugging that adding 0.25 rounded
// matches sizeThatFits: identically. Not sure why…
size.width += horzPadding + 0.25;
size.height += vertPadding + 0.25;
size = CGSizeRound(size);
return size;
}
Note, CGSizeRound is just a custom function I wrote that rounds the width and height of the CGSize to the nearest 0.5.
For comparison, if you create a second UITextView, and make sure the textContainer.lineFragmentPadding and textContainerInset are the same, you should see the values almost identical to the nearest 0.5.
And to your question about calculating a proper pointSize, this is some pseudo code for that:
CGFloat pointSize = 64;
CGFloat minPointSize = 32;
CGFloat decrementor = 4;
CGFloat padding = self.textContainerInset.left + self.textContainerInset.right + lineFragmentPaddings;
CGFloat actualWidth = self.maxTextViewSize.width - padding * 2;
CGRect boundingRect = CGRectZero;
BOOL isValidPointSize = NO;
do {
if (pointSize < minPointSize) {
pointSize = minPointSize;
boundingRect.size.height = self.maxTextViewSize.height;
isValidPointSize = YES;
} else {
NSDictionary *defaultAttributes = [self.customTextStorage defaultAttributesForPointSize:pointSize];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:string attributes:defaultAttributes];
boundingRect = [attrString boundingRectWithSize:CGSizeMake(actualWidth, 1024) options:NSStringDrawingUsesLineFragmentOrigin context:nil];
// is the height to big?
if (boundingRect.size.height > self.maxTextViewSize.height) {
// reduce the point size for next iteration of loop
pointSize -= decrementor;
}
// passes height test
else {
isValidPointSize = YES;
}
}
} while (!isValidPointSize);
return pointSize;
Again, the above is pseudo code based on my implementation (not meant for just drop in replacement for what you have). Hope this helps!
try like this
UITextView *textViewObj;//initialise textview.
textViewObj.autoresizesSubviews = NO;
textViewObj.autoresizingMask = UIViewAutoresizingNone;
This is really working in swift,get original height of textview.. try this
let
size = cellQueue.contentLbl.sizeThatFits(CGSizeMake(cellQueue.contentLbl.frame.size.width,CGFloat(MAXFLOAT))) cellQueue.heightConstraintContentLbl.constant = size.height

Autoadjust content of UILabel

I have already determined the bounds of UILabel. Single line, 2-3 words. I have to change the font size. What is the best solution to adjust the content into strongly determined rectangle programmatically?
Set the minimum font scale of the label
_myLabel.adjustsFontSizeToFitWidth = YES;
_myLabel.minimumScaleFactor = 0.5f;
Use Autoshrink property in your XIB (or programmatically) and set minimum Font Size and your text will be adapted to the space. But with a minimum font.
I found the solution to check the sizes manually. The other solutions are working improperly. May be this code will help to somebody. Here the code to solve:
-(void) autoResizeLabel: (UILabel*) label withMaxWidth:(CGFloat)mw withMaxHeight:(CGFloat)mh
{
CGFloat fontSize = 1.f;
CGFloat outSize = fontSize;
CGFloat mDelta = 30.f;
CGFloat delta = 1.f;
BOOL activated = NO;
BOOL broken = NO;
for (float fSize = fontSize; fSize < fontSize + mDelta; fSize += delta)
{
CGRect r = [label.text boundingRectWithSize:label.frame.size options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:fSize]} context:nil];
CGFloat width = r.size.width;
CGFloat height = r.size.height;
if (mw <= width || mh <= height)
{
if (activated)
{
outSize = fSize - delta;
}
broken = YES;
break;
}
activated = YES;
//NSLog(#"%f;%f;%f",fSize,mw,mh);
}
if (activated && !broken) outSize = fontSize + mDelta - delta;
[label setFont:[UIFont systemFontOfSize:outSize]];
}

How to resize UITextView text which fit on its frame after scale?

i do following code after scale uitextview but its not given me exact result
UITextView *textView = (UITextView *)[mainView viewWithTag:10];
int newFontSize,oldFontSize;
oldFontSize = textView.font.pointSize;
newFontSize =((textView.frame.size.height * textView.frame.size.width) * oldFontSize) / (textView.contentSize.height * textView.contentSize.width);
double olddistance = sqrt(pow((textView.frame.origin.x - (textView.frame.origin.x + textView.contentSize.width)), 2.0) + pow((textView.frame.origin.y - (textView.frame.origin.y + textView.contentSize.height)), 2.0));
double newDistance = sqrt(pow((textView.frame.origin.x - (textView.frame.origin.x + textView.frame.size.width)), 2.0) + pow((textView.frame.origin.y - (textView.frame.origin.y + textView.frame.size.height)), 2.0));
float scale = newDistance/olddistance;
float newWidth = scale * textView.contentSize.width;
float newHeight = scale * textView.contentSize.height;
self.frame = CGRectMake(self.frame.origin.x,self.frame.origin.y, newWidth+40, newHeight+40);
if (textView.font.pointSize * scale < 10)
{
textView.font = [UIFont fontWithName:textView.font.fontName size:10];
self.frame = CGRectMake(self.frame.origin.x,self.frame.origin.y, textView.contentSize.width,textView.contentSize.height);
}
else
{
textView.font = [UIFont fontWithName:textView.font.fontName size:textView.font.pointSize * scale];
}
I have once made a text view which resizes itself to exactly fit all the text in.
What you need is to provide the text and the width of your text view.
Here is the code:
-(CGSize) sizeForString:(NSString *)string WithWidth:(CGFloat)width {
CGSize size = [string sizeWithFont:[UIFont boldSystemFontOfSize:16]
constrainedToSize:CGSizeMake(width, MAXFLOAT)
lineBreakMode:NSLineBreakByWordWrapping];
return size;
}
The function returns the proper size for your text view, therefore, you may adjust the text view accordingly.

Calculate NSString size to adjust UITextField frame

I have issues calculating the accurate size of a NSString displayed in a UITextField.
My goal is to update the textfield frame size according to the string size programmatically (without using sizeToFit). I am using the sizeWithFont function.
-(void)resizeTextFieldAccordingToText:(NSString*)textFieldString {
CGPoint originalCenter = self.textField.center;
UIFont* currentFont = [textField font];
CGSize newSize = [textFieldString sizeWithFont:currentFont];
//Same incorrect results with the extended version of sizeWithFont, e.g.
//[textFieldString sizeWithFont:currentFont constrainedToSize:CGSizeMake(300.0, 100.0) lineBreakMode:NSLineBreakByClipping];
[self.textField setFrame:(CGRectMake(self.textField.frame.origin.x, self.textField.frame.origin.y, newSize.width, newSize.height))];
[self.textField setCenter:originalCenter];
}
Problem: While this return correct size results at first its becomes more and more unprecise by adding characters therefore finally starts clipping the string (as seen in the right screenshot).
How do I get the accurate size of the textField string for correctly adjusting its size?
UITextField has it's own layout inside if you use borderStyle != UITextBorderStyleNone. In this case you have to increase text size dimensions by some constants.
With UITextBorderStyleNone you don't have this problem, and code below works like a charm (iOS 7 introduced new method to get text size, -sizeWithFont: is deprecated)
- (IBAction)textChanged:(UITextField *)field
{
UIFont *font = field.font;
NSString *string = field.text;
CGSize size = [string sizeWithAttributes:
[NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]];
CGPoint center = field.center;
CGRect frame = field.frame;
frame.size = size; // or CGSizeMake(size.width + WIDTH_PADDING * 2, size.height + HEIGHT_PADDING * 2)
field.frame = frame;
field.center = center;
}
the problem is that you don't take into account the contentInset of the UITextField. Your code would be fine for a label not for a textfield.
for example: one way could be:
CGPoint originalCenter = self.textField.center;
UIFont* currentFont = [textField font];
CGSize oldSize = [self.textField.text sizeWithFont:currentFont];
CGSize newSize = [textFieldString sizeWithFont:currentFont];
CGRect finalFrame = self.textField.frame
finalFrame.size.width -= oldSize.width;
finalFrame.size.width += newSize.width;
finalFrame.size.height -= oldSize.height;
finalFrame.size.height += newSize.height;
[self.textField setFrame:finalFrame];
[self.textField setCenter:originalCenter];
ios7 deprecates sizeWithFont:currentFont so it is sizeWithAttributes:#{NSFontAttributeName:currentFont}

MBProgressHUD to show label text in more than one line

Hi i have a MBProgressHUD on my iPad screen. Works perfectly fine. But i want to change the label to show in three lines.Like this
self.hud = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
self.hud.frame = CGRectMake(0, 0, 120, 143);
[self.navigationController.view addSubview:self.hud];
self.hud.delegate = self;
self.hud.mode = MBProgressHUDModeAnnularDeterminate;
NSString *strloadingText = [NSString stringWithFormat:#"Loading Data.\r Please Wait.\r 1-2 Minutes"];
NSLog(#"the loading text will be %#",strloadingText);
self.hud.labelText = strloadingText;
[self.hud show:YES];
So i want the label in 3 lines
Loading Data.
Please Wait
1-2 Minutes
OR
can i assign an image to the HUD?
All this should be in the labeltext. But i am ending up with only one line. How can i do that?
If you need more info, please ask.Thanks.
MBProgressHUD's detailsLabelText property is multiline but not labelText property.
So, you can try something like this
MBProgressHUD * hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.frame = CGRectMake(0, 0, 120, 143);
hud.mode = MBProgressHUDModeAnnularDeterminate;
NSString *strloadingText = [NSString stringWithFormat:#"Loading Data."];
NSString *strloadingText2 = [NSString stringWithFormat:#" Please Wait.\r 1-2 Minutes"];
NSLog(#"the loading text will be %#",strloadingText);
hud.labelText = strloadingText;
hud.detailsLabelText=strloadingText2;
You can set detailsLabelText font by using the property detailsLabelFont.
I had a question like this, too !
You can set hud.label.numberOfLines = 0;
And it works!
The reason why labelText differs from detailsText, I imagine because it's meant to be a very similar to UIAlertView from the title/description perspective.
The differences between the two labels is quite distinct because of their purpose, for instance:
Titles have bigger fonts, oft times bold in comparison to detail text.
Titles are meant to be short and obvious, taken from a popular dictionary site (description speaks for itself):
Title: A descriptive name; an epithet.
I'd recommend not having a multi-line title, keeping it short, and using the description text.
The reason why multi-line titles do not work is because of the layoutSubviews implementation, the size is not being calculated. if you inspect MBProgressHud.m, within layoutSubviews,
CGFloat remainingHeight = bounds.size.height - totalSize.height - kPadding - 4 * margin;
CGSize maxSize = CGSizeMake(maxWidth, remainingHeight);
CGSize detailsLabelSize = [detailsLabel.text sizeWithFont:detailsLabel.font
constrainedToSize:maxSize lineBreakMode:detailsLabel.lineBreakMode];
totalSize.width = MAX(totalSize.width, detailsLabelSize.width);
totalSize.height += detailsLabelSize.height;
if (detailsLabelSize.height > 0.f && (indicatorF.size.height > 0.f || labelSize.height > 0.f)) {
totalSize.height += kPadding;
}
Note the -[NSString sizeWithFont: constrainedToSize: lineBreakMode:] call for the description text; this method calculates the size required to display the text - using as many lines as necessary, whereas the -[NSString sizeWithFont:] calculates the size required to display the text, but only up to displaying one line.
I would advise against having a multi-line title, and instead provide a shorter title, with some description text to accompany it.
If you simply must have the multi-line title (all changes within MBProgressHud.m):
- (void)setupLabels {
label = [[UILabel alloc] initWithFrame:self.bounds];
label.adjustsFontSizeToFitWidth = NO;
label.textAlignment = MBLabelAlignmentCenter;
label.opaque = NO;
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor whiteColor];
label.font = self.labelFont;
label.text = self.labelText;
>>> label.numberOfLines = 0;
[self addSubview:label];
...
Replace:
CGSize labelSize = [label.text sizeWithFont:label.font];
labelSize.width = MIN(labelSize.width, maxWidth);
totalSize.width = MAX(totalSize.width, labelSize.width);
totalSize.height += labelSize.height;
if (labelSize.height > 0.f && indicatorF.size.height > 0.f) {
totalSize.height += kPadding;
}
CGFloat remainingHeight = bounds.size.height - totalSize.height - kPadding - 4 * margin;
CGSize maxSize = CGSizeMake(maxWidth, remainingHeight);
CGSize detailsLabelSize = [detailsLabel.text sizeWithFont:detailsLabel.font
constrainedToSize:maxSize lineBreakMode:detailsLabel.lineBreakMode];
With:
CGFloat remainingHeight = bounds.size.height - totalSize.height - kPadding - 4 * margin;
CGSize maxSize = CGSizeMake(maxWidth, remainingHeight);
CGSize labelSize = [label.text sizeWithFont:label.font constrainedToSize:maxSize lineBreakMode:label.lineBreakMode];
totalSize.width = MAX(totalSize.width, labelSize.width);
totalSize.height += labelSize.height;
if (labelSize.height > 0.f && indicatorF.size.height > 0.f) {
totalSize.height += kPadding;
}
remainingHeight = bounds.size.height - totalSize.height - kPadding - 4 * margin;
CGSize detailsLabelSize = [detailsLabel.text sizeWithFont:detailsLabel.font
constrainedToSize:maxSize lineBreakMode:detailsLabel.lineBreakMode];
Hope this isn't too late to help.
self.hud.minSize = CGSizeMake(300, 100);

Resources