UILabel Shadow Has Unwanted Cut Off - ios

I have a UILabel that I add a shadow to. The UILabel shows up and so does the shadow, but the leftmost shadow is cut off so that it is in line with the edge of the text. I moved the position of the label to see if it was being covered by a view, but everything stayed the same. I also took out the sizeToFit, and it stayed the same. Here is the initialization of the label:
UILabel *scoreLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)];
scoreLabel.text = text;
[scoreLabel setFont:[UIFont fontWithName:fontName size:fontSize]];
scoreLabel.textColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
scoreLabel.shadowColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f];
scoreLabel.shadowOffset = CGSizeMake(-10.0, 2.0);
scoreLabel.clipsToBounds = NO;
[scoreLabel sizeToFit];
scoreLabel.center = CGPointMake(x, y);

I had this problem with a custom font and solved it by subclassing UILabel and adding the shadowOffset to intrinsicContentSize with this override:
override var intrinsicContentSize: CGSize {
get {
let s = super.intrinsicContentSize
return CGSize(width: s.width + abs(shadowOffset.width), height: s.height + abs(shadowOffset.height))
}
}

I think you need to add
scoreLabel.clipsToBounds = NO;

This is the solution you want:
let style = NSMutableParagraphStyle()
style.firstLineHeadIndent = someInset // can be shadowBlur and/or shadowRadius
style.headIndent = someInset
style.tailIndent = -someInset // must be negative since its at the end (tail)
let attrString = NSMutableAttributedString(string: "Some Text")
attrString.addAttribute(.paragraphStyle, value: style, range: .init(location: 0, attrString.length)
let label = UILabel()
label.numberOfLines = 0 // not necessary
label.attributedText = attrString

I added this and the cut off went away:
scoreLabel.textAlignment = NSTextAlignmentCenter;

Related

Drawing UILabel according to the string length

I am drawing label using drawRect and the code looks like something below.
if (productName && productName.length > 0) {
UILabel *productNameLabel = [[UILabel alloc]init];
productNameLabel.numberOfLines = 2;
productNameLabel.attributedText = [self shadowedTextWithString:productName fontName:#"ProximaNovaA-Light" fontSize:productNameLabelFontSize isOfferType:NO];
[productNameLabel sizeToFit];
//drawing the UILabel
[productNameLabel drawTextInRect:CGRectMake(25, labelYPosition, productNameLabel.frame.size.width, productNameLabel.frame.size.height)];
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 25, labelYPosition);
[productNameLabel.layer renderInContext:UIGraphicsGetCurrentContext()];
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -25, -labelYPosition);
labelYPosition += productNameLabel.frame.origin.y + productNameLabel.frame.size.height+20;
}
However, the productNameLabel.numberOfLiness = 2 doesn't seem to work at all... If the string has length that exceeds the width of the screen, the text is truncated and the UILabel stays one liner.
Anyone knows how do i do it, so that if the length of the string exceeds the width of screen, the exceeded words will go to the second line?
Thanks!
updated code, still doesn't work !
if (productName && productName.length > 0) {
UILabel *productNameLabel = [[UILabel alloc]init];
productNameLabel.lineBreakMode = YES;
productNameLabel.numberOfLines = 0;
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineBreakMode = NSLineBreakByTruncatingTail;
NSMutableAttributedString *productNameAttributedString = [self shadowedTextWithString:productName fontName:#"ProximaNovaA-Light" fontSize:productNameLabelFontSize isOfferType:NO];
[productNameAttributedString addAttribute:NSParagraphStyleAttributeName
value:style
range:NSMakeRange(0, productNameAttributedString.length)];
productNameLabel.attributedText = productNameAttributedString;
CGSize constrainedSize = CGSizeMake(paramImageView.image.size.width -50 , 9999);
CGRect requiredHeight = [productNameLabel.attributedText boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin context:nil];
if (requiredHeight.size.width > productNameLabel.frame.size.width) {
requiredHeight = CGRectMake(25,labelYPosition, productNameLabel.frame.size.width, requiredHeight.size.height);
}
CGRect newFrame = productNameLabel.frame;
newFrame.size.height = requiredHeight.size.height;
productNameLabel.frame = newFrame;
productNameLabel.backgroundColor = [UIColor redColor];
[productNameLabel drawTextInRect:CGRectMake(25, labelYPosition, paramImageView.image.size.width-50, requiredHeight.size.height)];
//[productNameLabel drawTextInRect:CGRectMake(25, labelYPosition, 30, productNameLabel.frame.size.height)];
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 25, labelYPosition);
[productNameLabel.layer renderInContext:UIGraphicsGetCurrentContext()];
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -25, -labelYPosition);
labelYPosition += productNameLabel.frame.origin.y + productNameLabel.frame.size.height+20;
}
Objective-c
CGSize sizeToFit = [title sizeWithFont:productNameLabel.font constrainedToSize:productNameLabel.frame.size lineBreakMode:productNameLabel.lineBreakMode];
Swift 2.2
var sizeToFit = title.sizeWithFont(productNameLabel.font, constrainedToSize: productNameLabel.frame.size, lineBreakMode: productNameLabel.lineBreakMode)
Swift3.0
var sizeToFit: CGSize = title.size(with: productNameLabel.font, constrainedTo: productNameLabel.frame.size, lineBreakMode: productNameLabel.lineBreakMode)
CGSize constrainedSize = CGSizeMake(self.resizableLable.frame.size.width , 9999);
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"HelveticaNeue" size:11.0], NSFontAttributeName,
nil];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:#"textToShow" attributes:attributesDictionary];
CGRect requiredHeight = [string boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin context:nil];
if (requiredHeight.size.width > self.resizableLable.frame.size.width) {
requiredHeight = CGRectMake(0,0, self.resizableLable.frame.size.width, requiredHeight.size.height);
}
CGRect newFrame = self.resizableLable.frame;
newFrame.size.height = requiredHeight.size.height;
self.resizableLable.frame = newFrame;
Implement this method to find width of string pass font as an argument you want to give to string and this method will return width of string.
func widthOfString(usingFont font: UIFont) -> CGFloat {
let fontAttributes = [NSFontAttributeName: font]
let size = self.size(attributes: fontAttributes)
return size.width
}
Set this width as a width of the UILabel
Swift-3:
Returns the height of label with padding depending on the text.
func heightForView(text: String, font: UIFont, width: CGFloat) -> CGFloat {
let label = UILabel(frame: CGRect.init(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height + labelHeightPadding ///extra padding; if needed be.
}

how to do truncation of text in UILabel

I have problem with truncation of text in UILabel even I have set lineBreakMode = NSLineBreakByWordWrapping perfectly.
Here is my code snippet :
lblSelectedText = [[UILabel alloc] init];
lblSelectedText.numberOfLines = 0;
lblSelectedText.lineBreakMode = NSLineBreakByWordWrapping;
lblSelectedText.font = [UIFont fontWithName:#"MyriadPro-Regular" size:(IS_IPAD_PRO?13.0:9.0)];
lblSelectedText.textAlignment = NSTextAlignmentCenter;
lblSelectedText.textColor = [UIColor lightGrayColor];
lblSelectedText.text = strKey; // Here text will be dynamic
CGFloat width = 150;
CGSize strSize = [self findHeightForText:strKey havingWidth:width andFont:lblSelectedText.font];
lblSelectedText.frame = CGRectMake(12, 10, CGRectGetWidth(aContainerController.view.frame)-20, strSize.height+15);
- (CGSize)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font
{
CGSize size = CGSizeZero;
if (text)
{
if (IS_ENGLISH) {
CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{ NSFontAttributeName:font } context:nil];
size = CGSizeMake(frame.size.width, frame.size.height + 10);
}
else {
CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{ NSFontAttributeName:font } context:nil];
size = CGSizeMake(frame.size.width, frame.size.height + 1);
}
}
return size;
}
Please note that these labels are in collection view cell. Here are some reference images.
If anyone have solution of this problem please share with me...
Thanks.
As you have mentioned in comment that some characters goes in to next line that means there is not enough width to fill every letter in single line thats why it is going to second line as you set number of line to 0(i.e. multiple lines). So there is nothing is wrong in it. It is normal behavior according to your setup made in code.
now if you want that it not goes to second line then set numberOfLines property to 1.
Another option is you can set minimunScaleFactor from 0 to 1 to resize your font to fit in available width.
You can do it something like,
label.adjustsFontSizeToFitWidth = YES;
label.minimumScaleFactor = 0.5f;
So, It will reduce font size to half of the actual to fit it in availabel width.
And once try by changing linebreakmode to NSLineBreakByTruncatingTail also instead of NSLineBreakByWordWrapping.
Check this:-
label.minimumScaleFactor = 0.5f;
label.lineBreakMode = NSLineBreakByTruncatingMiddle;
[label sizeToFit];

Add shadow to frame of UITextView add also shadow to text

I have a UITextView where I add some drop shadow to the frame, but when I write, the text got also the same shadow. How to avoid this problem?
My code :
commentary = [[UITextView alloc]initWithFrame:CGRectMake(10, 435, 230, 120)];
commentary.font = STANDARDFONT;
commentary.backgroundColor = BACKGROUND;
commentary.layer.shadowColor = [UIColor blackColor].CGColor;
commentary.layer.shadowOffset = CGSizeMake(2, 2);
commentary.layer.shadowOpacity = 0.8;
commentary.layer.shadowRadius = 2.0;
commentary.layer.borderColor = [UIColor grayColor].CGColor;
commentary.layer.borderWidth = 1.5;
commentary.layer.cornerRadius = 5;
commentary.layer.masksToBounds = NO;
commentary.clipsToBounds = NO;
[self addSubview:commentary];
BACKGROUND and STANDARDFONT is [UICOLOR clearColor].CGColorand [UIFont fontWithName:#"TimesNewRomanPSMT" size:16];
Try setting the layer background color also: commentary.layer.backgroundColor = BACKGROUND.CGColor

Resize UILabel based on content

I have a UILabel, his text size has the property
title.adjustsFontSizeToFitWidth = YES;
that prevents me from using standard methods to resize the UILabel. I read on another post here that I'm supposed to use the function
sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode
from this answer: How to figure out the font size of a UILabel when -adjustsFontSizeToFitWidth is set to YES?
Now, i can't figure out how to make it work.. this is the actual code
UIFont *font = [UIFont fontWithName:#"Marker Felt" size:200];
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, width, 20.0)];
title.text = #"this is a long title that should be resized";
title.font = font;
title.numberOfLines = 1;
title.adjustsFontSizeToFitWidth = YES;
CGFloat pointSize = 0.0;
CGSize size = [title.text sizeWithFont:font
minFontSize:title.minimumFontSize
actualFontSize:&pointSize
forWidth:width
lineBreakMode:title.lineBreakMode];
title.frame = CGRectMake(title.frame.origin.x,
title.frame.origin.y,
size.width,
size.height);
The UILabel get resized wrongly, as if the font size it's still 200..
Any clues? Thanks!
I have some code you could use on my github, check it out, it's a category for UILabel, you need to set the frame width and when you can resizeToFit on the UILabel, it adjusts the height to fit the content, and returns the y position of the end of the label so you can adjust any content appearing after it.
https://gist.github.com/1005520
I'd suggest filing this as a bug.
The size returned by -sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode: has the correct width, but not the height does not account for the actual font size.
It seems likely that UILabel also has this bug. Changing the size of a label to match the height of the text in a font of the size returned by -sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode: will incorrectly vertically position the text within the label.
A work-around is to calculate the correct height, and change the font on the label to with the actual font size:
CGFloat pointSize = 0.0f;
CGRect frame = title.frame;
frame.size = [title.text sizeWithFont:font
minFontSize:title.minimumFontSize
actualFontSize:&pointSize
forWidth:width
lineBreakMode:title.lineBreakMode];
UIFont *actualFont = [UIFont fontWithName:#"Marker Felt" size:pointSize];
CGSize sizeWithCorrectHeight = [title.text sizeWithFont:actualFont];
frame.size.height = sizeWithCorrectHeight.height;
title.frame = frame;
title.font = actualFont;
Try to create font with smaller fontSize. For example:
UIFont *font = [UIFont fontWithName:#"Marker Felt" size:20];
but to actualFontSize pass link to CGFloat == 200.
UPDATED:
try this then:
UIFont *font = [UIFont fontWithName:#"Marker Felt" size:20];
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, width, 20.0)];
title.text = #"this is a long title that should be resized";
title.font = font;
title.numberOfLines = 1;
title.adjustsFontSizeToFitWidth = YES;
CGFloat pointSize = 0.0;
CGSize size = [title.text sizeWithFont:font minFontSize:title.minimumFontSize actualFontSize:&pointSize forWidth:width lineBreakMode:title.lineBreakMode];
title.frame = CGRectMake(title.frame.origin.x, title.frame.origin.y, size.width, size.height);
font = [UIFont fontWithName:#"Marker Felt" size:200];
title.font = font;
UILabel * label = [[UILabel alloc] init];
[label setNumberOfLines:0];
label.text=[detailDict valueForKey:#"method"];
[label setFont:[UIFont fontWithName:#"Georgia" size:16.0]];
CGSize labelsize=[label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(250, 1000.0) lineBreakMode:UILineBreakModeWordWrap];
int y=0;
label.frame=CGRectMake(38, y, 245, labelsize.height);
[label setBackgroundColor:[UIColor clearColor]];
[label setTextColor:[UIColor whiteColor]];
scrollView.showsVerticalScrollIndicator = NO;
y+=labelsize.height;
[scrollView setContentSize:CGSizeMake(200,y+50)];
[scrollView addSubview:label];
[label release];
I think you should use this code and i am using the label on scrollview for a big text you can also do so
Have you tried intrinsicContentSize?
myLable.numberOfLines = 0
myLable.frame = CGRect(x: 10, y: 10, width: 300, height: lblSuperscript.intrinsicContentSize().height)

How to calculate UILabel width based on text length?

I want to display an image next to a UILabel, however UILabel has variable text length, so I don't know where to place the image. How can I accomplish this?
CGSize expectedLabelSize = [yourString sizeWithFont:yourLabel.font
constrainedToSize:maximumLabelSize
lineBreakMode:yourLabel.lineBreakMode];
What is -[NSString sizeWithFont:forWidth:lineBreakMode:] good for?
this question might have your answer, it worked for me.
For 2014, I edited in this new version, based on the ultra-handy comment by Norbert below! This does everything.
// yourLabel is your UILabel.
float widthIs =
[self.yourLabel.text
boundingRectWithSize:self.yourLabel.frame.size
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{ NSFontAttributeName:self.yourLabel.font }
context:nil]
.size.width;
NSLog(#"the width of yourLabel is %f", widthIs);
yourLabel.intrinsicContentSize.width for Objective-C / Swift
In swift
yourLabel.intrinsicContentSize().width
The selected answer is correct for iOS 6 and below.
In iOS 7, sizeWithFont:constrainedToSize:lineBreakMode: has been deprecated. It is now recommended you use boundingRectWithSize:options:attributes:context:.
CGRect expectedLabelSize = [yourString boundingRectWithSize:sizeOfRect
options:<NSStringDrawingOptions>
attributes:#{
NSFontAttributeName: yourString.font
AnyOtherAttributes: valuesForAttributes
}
context:(NSStringDrawingContext *)];
Note that the return value is a CGRect not a CGSize. Hopefully that'll be of some assistance to people using it in iOS 7.
Swift 4 Answer who are using Constraint
label.text = "Hello World"
var rect: CGRect = label.frame //get frame of label
rect.size = (label.text?.size(attributes: [NSFontAttributeName: UIFont(name: label.font.fontName , size: label.font.pointSize)!]))! //Calculate as per label font
labelWidth.constant = rect.width // set width to Constraint outlet
Swift 5 Answer who are using Constraint
label.text = "Hello World"
var rect: CGRect = label.frame //get frame of label
rect.size = (label.text?.size(withAttributes: [NSAttributedString.Key.font: UIFont(name: label.font.fontName , size: label.font.pointSize)!]))! //Calculate as per label font
labelWidth.constant = rect.width // set width to Constraint outlet
In iOS8 sizeWithFont has been deprecated, please refer to
CGSize yourLabelSize = [yourLabel.text sizeWithAttributes:#{NSFontAttributeName : [UIFont fontWithName:yourLabel.font size:yourLabel.fontSize]}];
You can add all the attributes you want in sizeWithAttributes.
Other attributes you can set:
- NSForegroundColorAttributeName
- NSParagraphStyleAttributeName
- NSBackgroundColorAttributeName
- NSShadowAttributeName
and so on. But probably you won't need the others
CGRect rect = label.frame;
rect.size = [label.text sizeWithAttributes:#{NSFontAttributeName : [UIFont fontWithName:label.font.fontName size:label.font.pointSize]}];
label.frame = rect;
Here's something I came up with after applying a few principles other SO posts, including Aaron's link:
AnnotationPin *myAnnotation = (AnnotationPin *)annotation;
self = [super initWithAnnotation:myAnnotation reuseIdentifier:reuseIdentifier];
self.backgroundColor = [UIColor greenColor];
self.frame = CGRectMake(0,0,30,30);
imageView = [[UIImageView alloc] initWithImage:myAnnotation.THEIMAGE];
imageView.frame = CGRectMake(3,3,20,20);
imageView.layer.masksToBounds = NO;
[self addSubview:imageView];
[imageView release];
CGSize titleSize = [myAnnotation.THETEXT sizeWithFont:[UIFont systemFontOfSize:12]];
CGRect newFrame = self.frame;
newFrame.size.height = titleSize.height + 12;
newFrame.size.width = titleSize.width + 32;
self.frame = newFrame;
self.layer.borderColor = [UIColor colorWithRed:0 green:.3 blue:0 alpha:1.0f].CGColor;
self.layer.borderWidth = 3.0;
UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(26,5,newFrame.size.width-32,newFrame.size.height-12)];
infoLabel.text = myAnnotation.title;
infoLabel.backgroundColor = [UIColor clearColor];
infoLabel.textColor = [UIColor blackColor];
infoLabel.textAlignment = UITextAlignmentCenter;
infoLabel.font = [UIFont systemFontOfSize:12];
[self addSubview:infoLabel];
[infoLabel release];
In this example, I'm adding a custom pin to a MKAnnotation class that resizes a UILabel according to the text size. It also adds an image on the left side of the view, so you see some of the code managing the proper spacing to handle the image and padding.
The key is to use CGSize titleSize = [myAnnotation.THETEXT sizeWithFont:[UIFont systemFontOfSize:12]]; and then redefine the view's dimensions. You can apply this logic to any view.
Although Aaron's answer works for some, it didn't work for me. This is a far more detailed explanation that you should try immediately before going anywhere else if you want a more dynamic view with an image and resizable UILabel. I already did all the work for you!!

Resources