MBProgressHUD to show label text in more than one line - ios

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);

Related

Incompatible pointer types xcode 8

Hello Having some issue with my code.
Please dont judge, first time trying to figure out some errors. Im receiving a "incompatible pointer types sending 'UIFount*'to parameter of type 'NSDictionary*_Nullable'"
Here is the code. any help is appreciated...
// Entirely cover the parent view
UIView *parent = self.superview;
if (parent) {
self.frame = parent.bounds;
}
CGRect bounds = self.bounds;
// Determine the total widt and height needed
CGFloat maxWidth = bounds.size.width - 4 * margin;
CGSize totalSize = CGSizeZero;
CGRect indicatorF = indicator.bounds;
indicatorF.size.width = MIN(indicatorF.size.width, maxWidth);
totalSize.width = MAX(totalSize.width, indicatorF.size.width);
totalSize.height += indicatorF.size.height;
//**Issue is HERE**
CGSize labelSize = [label.text sizeWithAttributes: 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 sizeWithAttributes: 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;
}
totalSize.width += 2 * margin;
totalSize.height += 2 * margin;
sizeWithAttribute expect a NSDictionary and you are passing UIFont in it, that's why you are getting this warning, make a dictionary like this
NSDictionary *attributes = #{NSFontAttributeName: [UIFont fontWithName:#"YourFontName" size:YourFontSize]};
And then pass this attributes dictionary
CGSize labelSize = [label.text sizeWithAttributes: attributes];

kCTUnderlineStyleSingle is not working for some character

I am using NSAttributedstring with the attribute kCTUnderlineStyleSingle.
Character is underlining properly. But some character like g, q, p are not visible properly.
Even user cannot differentiate between g and q.
Is there any solution for that?
You can fix it using this method:
- (void)addUnderlineWithRange:(NSRange)range
{
int lineThickness = [EnvUtils isIpadEnv] ? 2 : 1;
UIColor *lineColor = self.textColor;
NSString *string = self.text;
CGRect labelFrame = self.frame;
CGSize expectedLabelSize = [NSString getMultilineTextSize:[string substringWithRange:range] forMaxSize:labelFrame.size font:self.font];
CGSize expectedLabelFullSize = [NSString getMultilineTextSize:string forMaxSize:labelFrame.size font:self.font];
CGSize xOffset = [NSString getMultilineTextSize:[string substringWithRange:NSMakeRange(0, range.location)] forMaxSize:labelFrame.size font:self.font];
CGFloat originX = (labelFrame.size.width - expectedLabelFullSize.width) / 2 + xOffset.width;
CGFloat originY = expectedLabelSize.height + (labelFrame.size.height - expectedLabelFullSize.height) / 2;
CGRect lineFrame = CGRectMake(originX, originY, expectedLabelSize.width, lineThickness);
UIView *lineView = [[[UIView alloc] initWithFrame:lineFrame] autorelease];
lineView.backgroundColor = lineColor;
[self.superview addSubview:lineView];
}

UITextView contentsize.height issue in iOS 7

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.

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.

How to calculate actual font point size in iOS 7 (not the bounding rectangle)?

Edit: The linked "duplicate" question only deals with calculating text rectangle. I need to calculate actual font size after label scaled it, NOT the string size.
This method is now deprecated:
size = [self sizeWithFont:font // 20
minFontSize:minFontSize // 14
actualFontSize:&actualFontSize // 16
forWidth:maxWidth
lineBreakMode:self.lineBreakMode];
How can I calculate font size of a UILabel now in iOS 7 when it shrunk the size of the text to fit in?
I have the same problem, I need to know the actual size to make that the others UILabels in my UIView match.
I know that it's not a perfect solution, but perhaps it's useful for you.
My solution is: instead of use adjustsFontSizeToFitWidth I calculate "manually" the size.
CGSize initialSize = [_label.text sizeWithAttributes:#{NSFontAttributeName:_label.font}];
while ( initialSize.width > _label.frame.size.width ) {
[_label setFont:[_label.font fontWithSize:_label.font.pointSize - 1]];
initialSize = [_label.text sizeWithAttributes:#{NSFontAttributeName:_label.font}];
}
CGFloat actualSize = _label.font.pointSize;
Distilled from Julius Bahr's answer on this page, this method works perfectly for getting the actual font size after it has been automatically adjusted:
- (CGFloat)getActualFontSizeForLabel:(UILabel *)label
{
NSStringDrawingContext *labelContext = [NSStringDrawingContext new];
labelContext.minimumScaleFactor = label.minimumScaleFactor;
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:label.text attributes:#{ NSFontAttributeName: label.font }];
[attributedString boundingRectWithSize:label.frame.size
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
context:labelContext];
CGFloat actualFontSize = label.font.pointSize * labelContext.actualScaleFactor;
return actualFontSize;
}
I am using this in my application to get the font sizes for three different labels for which I need to keep the sizes in synch while still allowing them to auto-shrink for localized translations that can be quite a bit longer than their original English counterparts.
I call that method once for each label, and then if they are not all the same value, I set the label's font sizes to the minimum of the three.
The use of minFontSize was deprecated on UILabel in iOS 6, and on the NSString drawing additions in iOS 7. If you want to use it and find the actual font size used, you need to use the deprecated method you mentioned in your question.
The replacement for minFontSize is minimumScaleFactor. If you want to find the actual scale factor used, you need to create an NSStringDrawingContext and pass it in the boundingRectWithSize:options:attributes:context: message, like this:
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
context.minimumScaleFactor = 0.7;
[label.text boundingRectWithSize:CGSizeMake(maxWidth, HUGE_VAL)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{
NSFontAttributeName: font
} context:context];
CGFloat actualFontSize = font.pointSize * context.actualScaleFactor;
Expanding on Ferran's answer
To expand to fill width or height, whichever it hits first
Swift version
func getFontSizeToFitFrameOfLabel(label: UILabel) -> CGFloat
{
var initialSize : CGSize = label.text!.sizeWithAttributes([NSFontAttributeName : label.font])
if initialSize.width > label.frame.size.width ||
initialSize.height > label.frame.size.height
{
while initialSize.width > label.frame.size.width ||
initialSize.height > label.frame.size.height
{
label.font = label.font.fontWithSize(label.font.pointSize - 1)
initialSize = label.text!.sizeWithAttributes([NSFontAttributeName : label.font])
}
} else {
while initialSize.width < label.frame.size.width &&
initialSize.height < label.frame.size.height
{
label.font = label.font.fontWithSize(label.font.pointSize + 1)
initialSize = label.text!.sizeWithAttributes([NSFontAttributeName : label.font])
}
// went 1 point too large so compensate here
label.font = label.font.fontWithSize(label.font.pointSize - 1)
}
return label.font.pointSize;
}
Then do something like this to use it (say your label is named title1Label)
title1Label.frame = CGRect(x: 0.0, y: 0.0, width: view.frame.size.width, height: view.frame.size.height)
// sets font to some nonzero size to begin with, it will change up or down to fit the label's frame
title1Label.font = UIFont(name: "Super Mario 256", size: 45.0)
title1Label.font = title1Label.font.fontWithSize(getFontSizeToFitFrameOfLabel(title1Label))
// resize height to be a little larger than the font height
title1Label.frame.size.height = title1Label.font.pointSize*1.3
Objective C version:
- (CGFloat) maxFontSize:(UILabel *)label{
CGSize initialSize = [label.text sizeWithAttributes:#{NSFontAttributeName:label.font}];
if (initialSize.width > label.frame.size.width ||
initialSize.height > label.frame.size.height)
{
while (initialSize.width > label.frame.size.width ||
initialSize.height > label.frame.size.height)
{
[label setFont:[label.font fontWithSize:label.font.pointSize - 1]];
initialSize = [label.text sizeWithAttributes:#{NSFontAttributeName:label.font}];
}
} else {
while (initialSize.width < label.frame.size.width &&
initialSize.height < label.frame.size.height)
{
[label setFont:[label.font fontWithSize:label.font.pointSize + 1]];
initialSize = [label.text sizeWithAttributes:#{NSFontAttributeName:label.font}];
}
// went 1 point too large so compensate here
[label setFont:[label.font fontWithSize:label.font.pointSize - 1]];
}
return label.font.pointSize;
}
My specific quest has been to size the font on 2 labels equally with adjustsFontSizeToFitWidth enabled.
The solution works on iOS 6 and 7.
+ (void)sizeLabelFontToMinSizeFor:(UILabel *)label1 and:(UILabel *)label2 {
NSStringDrawingContext *labelContext = [NSStringDrawingContext new];
labelContext.minimumScaleFactor = label1.minimumScaleFactor;
NSAttributedString *attributedString1 = [[NSAttributedString alloc] initWithString:label1.text attributes:#{NSFontAttributeName : label1.font}];
// the NSStringDrawingUsesLineFragmentOrigin and NSStringDrawingUsesFontLeading options are magic
[attributedString1 boundingRectWithSize:label1.frame.size options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:labelContext];
CGFloat actualFontSize1 = label1.font.pointSize * labelContext.actualScaleFactor;
labelContext = [NSStringDrawingContext new];
labelContext.minimumScaleFactor = label2.minimumScaleFactor;
NSAttributedString *attributedString2 = [[NSAttributedString alloc] initWithString:label2.text attributes:#{NSFontAttributeName : label2.font}];
[attributedString2 boundingRectWithSize:label2.frame.size options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:labelContext];
CGFloat actualFontSize2 = label2.font.pointSize * labelContext.actualScaleFactor;
CGFloat minSize = MIN(actualFontSize1, actualFontSize2);
label1.font = [UIFont fontWithName:RCDefaultFontName size:minSize];
label2.font = [UIFont fontWithName:RCDefaultFontName size:minSize];
}
Next code doesn't support minFontSize and lineBreakMode so if you need them you should improve it by yourself:
CGSize NSString_sizeWithFont(NSString * str, UIFont *font) {
CGSize result;
if (NO == [str respondsToSelector: #selector(sizeWithAttributes:)]) {
// legacy way
result = [str sizeWithFont: font];
} else {
// modern way
NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName, nil];
result = [str sizeWithAttributes: dict];
}
return result;
}
UIFont * NSString_calcActualFont(NSString * str, UIFont * initialFont,
CGSize sizeLimit, CGSize * actualSize)
{
const CGSize curSize = NSString_sizeWithFont(str, initialFont);
CGFloat actualFontSize = initialFont.pointSize;
actualFontSize *= MIN(sizeLimit.width / curSize.width, sizeLimit.height / curSize.height);
UIFont * actualFont = [initialFont fontWithSize: floorf(actualFontSize)];
*actualSize = NSString_sizeWithFont(str, actualFont);
return actualFont;
}
Simple solution for one-line UILabel:
//myLabel - initial label
UILabel *fullSizeLabel = [UILabel new];
fullSizeLabel.font = myLabel.font;
fullSizeLabel.text = myLabel.text;
[fullSizeLabel sizeToFit];
CGFloat actualFontSize = myLabel.font.pointSize * (myLabel.bounds.size.width / fullSizeLabel.bounds.size.width);
//correct, if new font size bigger than initial
actualFontSize = actualFontSize < myLabel.font.pointSize ? actualFontSize : myLabel.font.pointSize;
Erik van der Neut's code worked for me, so I translated it in Swift and wrapped it in a UILabel extension:
extension UILabel {
public func actualFontSize()-> CGFloat {
let context = NSStringDrawingContext()
context.minimumScaleFactor = self.minimumScaleFactor
let attributedString = NSAttributedString(string: self.text ?? "", attributes: [NSFontAttributeName: self.font])
attributedString.boundingRectWithSize(self.frame.size, options: [.UsesLineFragmentOrigin], context: context)
return (self.font.pointSize * context.actualScaleFactor)
}
}

Resources