UILabel Attributed Text rendering incorrectly - ios

I've been setting a UILabel using attributed text to get the font outlining that I want, and I change the UILabel's attributedText property fairly often. It seems that roughly 50% of the time it appears to render the new text OVER the old text without removing the old one. Right now my code looks like this:
// Attributes initialization
self.labelAttributes = [NSMutableDictionary dictionary];
[self.labelAttributes setObject: [UIFont fontWithName:#"Helvetica Neue" size:21] forKey: NSFontAttributeName];
[self.labelAttributes setObject: [UIColor whiteColor] forKey: NSForegroundColorAttributeName];
[self.labelAttributes setObject: [NSNumber numberWithFloat: -3.0] forKey: NSStrokeWidthAttributeName];
[self.labelAttributes setObject: [UIColor blackColor] forKey: NSStrokeColorAttributeName];
// Clear UILabel attributedString
self.userLabel.attributedText = [[NSAttributedString alloc] initWithString:#"" attributes:self.labelAttributes];
// Also attempted this with nil;
// Set UILabel to string, where self.userName and self.userAge are just regular strings.
NSString *labelString = [NSString stringWithFormat:#"%#, %#", self.userName, self.userAge];
self.userLabel.attributedText = [[NSAttributedString alloc] initWithString:labelString attributes:self.labelAttributes];
When it works, it looks like this:
When it doesn't work, it looks like this:
This appears to be the last user's name, plus the current user's name overlayed on top of each other.
I can't figure out a good way to guarantee the label is cleared, and am not sure how to debug it. (I've tried using visual debugging in XCode 6, but it still thinks it's just one label, with the new user's text as the text attribute.)

It should already be correct by default but you could try it anyway:
self.userLabel.clearsContextBeforeDrawing = YES;
self.userLabel.contentMode = UIViewContentModeRedraw;

Interesting. Don't really know why that isn't working. Your code seems fine. Only thing I can think of is that if this is a label in a table view cell and it being reset after it is offscreen and then on screen? Otherwise, no idea.
Here is another way of doing the same thing that works for me.
NSString *labelString = [NSString stringWithFormat:#"%#, %#", self.userName, self.userAge];
self.userLabel.text = labelString;
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc]initWithAttributedString:self.userLabel.attributedText];
[attStr addAttribute:NSFontAttributeName value:[UIFont fontWithName:#"Helvetica Neue" size:21] range:NSMakeRange(0, self.userLabel.length)];
[attStr addAttribute:NSForegroundColorAttributeName value:[UIColor whiteColor] range:NSMakeRange(0, self.userLabel.length)];
[attStr addAttribute:NSStrokeWidthAttributeName value:[NSNumber numberWithFloat:-3.0f] range:NSMakeRange(0, self.userLabel.length)];
[attStr addAttribute:NSStrokeColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0, self.userLabel.length)];
//or 1 liner
//[attStr addAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIFont fontWithName:#"Helvetica Neue" size:21], NSFontAttributeName, [UIColor whiteColor], NSForegroundColorAttributeName, [NSNumber numberWithFloat:-3.0f], NSStrokeWidthAttributeName, [UIColor blackColor], NSStrokeColorAttributeName, nil] range:NSMakeRange(0, self.userLabel.length)];
[self.userLabel setAttributedText:attStr];
Also, I don't see why you just can't set the label to have those properties to begin with, (if they are not changing throughout the label).
You could just do:
NSString *labelString = [NSString stringWithFormat:#"%#, %#", self.userName, self.userAge];
self.userLabel.text = labelString;
self.userLabel.font = [UIFont fontWithName:#"Helvetica Neue" size:21];
self.userLabel.textColor = [UIColor blackColor];
//Then set the stroke with one attribute
Hope this helps! Happy coding.

You can do it as followed:
self.userLabel.attributedText = [[NSAttributedString alloc]
initWithString:#"string to both stroke and fill"
attributes:#{
NSStrokeWidthAttributeName: [NSNumber numberWithFloat:-3.0],
NSStrokeColorAttributeName: [UIColor blackColor],
NSForegroundColorAttributeName: [UIColor whiteColor]
}
];

I suspect that the problem is not related with the attributed text. I suspect that the problem is that you are adding a new UILabel in a reused UITableViewCell, instead of reuse the old UILabel.

I think I've seen this happen before with UITableCell reuse and dynamic table cell heights, determined at run time. This happens when cells are being set to height 0, if I remember correctly.
If you're in the above scenario, try turning clipsToBounds to on on the UITableViewCell, or the topmost reused view. Turning on clipsToBounds causes the labels, etc. to not flow out of the view when the containing view's frame size or height has been set to zero.

Related

Attributed UITextView doesn't work with Korean symbols

Attributed UITextView doesn't work with Korean symbols. Steps to reproduce:
Add UITextView to the form.
Use the following code:
NSDictionary *attributes = #{
NSFontAttributeName:[UIFont fontWithName:#"HelveticaNeue" size:15],
NSForegroundColorAttributeName:[UIColor blackColor]};
[textView setAttributes:attributes
range:NSMakeRange(0, textView.text.length)];
Run the application, type any text on Korean (에서 보냄) and tap or press Enter.
The Korean text will disappear or will be replaced by several trash symbols. Why? How can I fix it?
P.S. The is an interesting answer on the question UITextField text disappears on every other keystroke But I'm creating UITextView object on the code.
Use This code it will help you.
//[_txtViewChallangeDescription setBackgroundColor:[UIColor redColor]];
_txtViewChallangeDescription.font = [UIFont fontWithName:kFontHelvetica size:kFontSize14];
[_txtViewChallangeDescription setTextColor:[UIColor blackColor]];
[_txtViewChallangeDescription setEditable:NO];
_txtViewChallangeDescription.delegate=self;
_txtViewChallangeDescription.scrollEnabled=NO;
_txtViewChallangeDescription.textContainer.lineFragmentPadding = 0;
_txtViewChallangeDescription.textContainerInset = UIEdgeInsetsZero;
NSDictionary *attrDict = #{
NSFontAttributeName : [UIFont fontWithName:kFontHelvetica size:kFontSize14],
NSForegroundColorAttributeName :[UIColor colorWithRed:152.0/255.0f green:132.0/255.0f blue:43.0/255.0f alpha:1.0f]
};
[_txtViewChallangeDescription setLinkTextAttributes:attrDict];
The following incorrect code works fine:
NSDictionary *attributes = #{
NSFontAttributeName:[/*UIFont fontWithName:#"HelveticaNeue" size:15],*/
NSForegroundColorAttributeName:[UIColor blackColor]};
[textView addAttributes:attributes
range:NSMakeRange(0, textView.text.length)];

Setting attributedText of UILabel causing issue with Lengthier content

In my project I want to add an attributed text in UILabel placed on the xib.
It's working perfectly, but if large text appears it shows some issues.
My current implementation:
- (void)viewDidLoad
{
[super viewDidLoad];
_demoLabel.numberOfLines = 0;
_demoLabel.lineBreakMode = NSLineBreakByWordWrapping;
_demoLabel.attributedText = [self demoNameWithFontSize:21 andColor:[UIColor redColor]];
}
- (NSMutableAttributedString *)demoNameWithFontSize:(CGFloat)fontSize andColor:(UIColor *)color
{
NSMutableAttributedString *attributedText = nil;
NSString *demoName = #"Blah blah blah";
UIFont *demoFont = [UIFont fontWithName:#"Zapfino" size:fontSize];
attributedText = [[NSMutableAttributedString alloc] initWithString:demoName];
NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
paragraph.lineBreakMode = NSLineBreakByWordWrapping;
[attributedText addAttribute:NSParagraphStyleAttributeName value:paragraph range:NSMakeRange(0, [demoName length])];
[attributedText addAttribute:NSFontAttributeName value:demoFont range:NSMakeRange(0, [demoName length])];
[attributedText addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(0, [demoName length])];
return attributedText;
}
Output:
Issue:
It is not displaying the whole text, even if I applied the NSMutableParagraphStyle.
How can I solve this ?
Alternative I found:
If I change
UIFont *demoFont = [UIFont fontWithName:#"Zapfino" size:fontSize];
to
UIFont *demoFont = [UIFont systemFontOfSize:fontSize];
It'll work and gives output like:
But the issue is I need to use custom font, can't use default font. Also cannot change the font size.
I checked UILabel class reference and googled, but couldn't find a solution. Please help me.
Is there anyway to span this text into multiple lines ?
You need to resize the UILabel to fit the text.
You can calculate the size with the boundingRectWithSize:options:context: NSAttributedString class method, which takes an attributed string and calculates the size within a set rect based on all the attributes of the string.

NSMutableAttributedString UILabel is not retaining its attributes when selected

I am having issues with retaining an attributed NSMutableString. I have a UITableView who's each UITableViewCell has an attributed text. Setting the attributed text is no problem, but upon selection, the UITableViewCell's attributes is lost. This is my code in cellForRowAtIndexPath that sets the attribute:
NSMutableAttributedString *changesStyleString_h = [[NSMutableAttributedString alloc] initWithString:#"Attributes change!" attributes:#{NSFontAttributeName: [UIFont boldSystemFontOfSize:20], NSForegroundColorAttributeName:[UIColor yellowColor]}];
[changesStyleString_h addAttributes:#{ NSUnderlineStyleAttributeName:#(1)} range:NSMakeRange(11, 6)];
cell.mainLabel.attributedText = changesStyleString
might i point out that mainLabel is also a UILabel, no customization there. Any help in the right direction would be greatly appreciated!
I found that I needed to set attributes on the ENTIRE string, or it would do funky things.
NSString* string = #"1 - some string"
NSMutableAttributedString* string = [[NSMutableAttributedString alloc] initWithString:string];
[string setAttributes:#{NSForegroundColorAttributeName: accent, NSFontAttributeName: [UIFont fontWithName:#"HelveticaNeue-Bold" size:13.f]} range:NSMakeRange(0, 1)];
This would cause weird behavior when highlighting the cell.
However, when I did this:
[string setAttributes:#{NSForegroundColorAttributeName: [UIColor blackColor]} range:NSMakeRange(1, [labelTwo length] - 1)];
Everything seemed to work as expected.
Hope that helps!

How can I set the color and alignment of attributed text in a UITextView in iOS 7?

The formatting of my textViews worked fine in iOS 6, but no longer in iOS 7. I understand with Text Kit much of the under the hood stuff has changed. It's become really quite confusing, and I'm hoping someone can help straighten it out a bit by helping me with something as simple as this.
My static UITextView originally was assigned a value for it's textColor and textAlignment properties. Then I made a NSMutableAttributedString, assigned it an attributes, then assigned it to the textView's attributedText property. The alignment and color no longer take effect in iOS 7.
How can I fix this? If these properties take no effect, than why do they exist anymore? Here's the creation of the textView:
UITextView *titleView = [[UITextView alloc]initWithFrame:CGRectMake(0, 90, 1024, 150)];
titleView.textAlignment = NSTextAlignmentCenter;
titleView.textColor = [UIColor whiteColor];
NSMutableAttributedString *title = [[NSMutableAttributedString alloc]initWithString:#"Welcome"];
UIFont *font = [UIFont fontWithName:#"Avenir-Light" size:60];
[title addAttribute:NSParagraphStyleAttributeName value:font range:NSMakeRange(0, title.length)];
titleView.attributedText = title;
[self.view addSubview:titleView];
Curious, the properties are taken into account for UILabel but not for UITextView
Why don't you just add attributes for color and alignment to the attributed string similar to the way you are doing with the font?
Something like:
NSMutableAttributedString *title = [[NSMutableAttributedString alloc]initWithString:#"Welcome"];
UIFont *font = [UIFont fontWithName:#"Avenir-Light" size:60];
[title addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, title.length)];
//add color
[title addAttribute:NSForegroundColorAttributeName value:[UIColor whiteColor] range:NSMakeRange(0, title.length)];
//add alignment
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setAlignment:NSTextAlignmentCenter];
[title addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, title.length)];
titleView.attributedText = title;
Edit: Assign the text first, then change the properties and this way it works.
UITextView *titleView = [[UITextView alloc]initWithFrame:CGRectMake(0, 90, 1024, 150)];
//create attributed string and change font
NSMutableAttributedString *title = [[NSMutableAttributedString alloc]initWithString:#"Welcome"];
UIFont *font = [UIFont fontWithName:#"Avenir-Light" size:60];
[title addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, title.length)];
//assign text first, then customize properties
titleView.attributedText = title;
titleView.textAlignment = NSTextAlignmentCenter;
titleView.textColor = [UIColor whiteColor];

UILabel with different fonts

I have this string that I want to display in a label:
NSString *criticsScore=[NSString stringWithFormat:#"%#\%%",[dict objectForKey:#"critics_score"]];
_criticRating.text=criticsScore;
I want to set a small font for \%% and a large font for [dict objectForKey:#"critics_score"]];
Is this possible?
You Need to use your own control for drawing an NSAttributedString, like TTTAttributedLabel.
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"Blah1:blah-blah%d. Blah2:-%d%%", [currentCoupon.couponPrice intValue],[currentCoupon.couponDiscountPercent intValue]];
[str addAttribute:NSBackgroundColorAttributeName value:[UIColor clearColor] range:NSMakeRange(0,30)];/// Define Range here and also BackGround color which you want
[str addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0,30)];/// Define Range here and also TextColor color which you want
[str addAttribute:NSFontAttributeName value:[UIFont fontWithName:#"HelveticaNeue-Bold" size:20.0] range:NSMakeRange(20, 10)];
lblWithText.attributedText = str;
Above Code I got From How to use multiple font stylings on a single string inside a label?
Read this post. It is about NSAttributedStrings. I think that is what you need.
You would have to do it with two UILabels. You would set the first label to be all of the text excpt the \%%, and get the size of that label using sizeWithFont: on the text that goes in that label. Then set the second label to start at the end of that label's frame.
So, it would look something like this, changing the coordinates based on where you want the labels:
NSString *criticsScore = [NSString stringWithFormat:#"%#",[dict objectForKey:#"critics_score"]];
NSString *str2 = #"\%%";
UIFont *criticsFont = [UIFont systemFontOfSize:[UIFont systemFontSize]];
UIFont *font2 = [UIFont systemFontOfSize:12.0];
//Get the sizes of each text string based on their font sizes.
CGSize criticsSize = [criticsScore sizeWithFont:criticsFont];
CGSize size2 = [str2 sizeWithFont:font2];
int x = 0;
int y = 0;
//The first label will start at whatever x and y are.
UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMake(x,y,criticsSize.width,criticsSize.height)];
[label1 setFont:criticsFont];
//Create a second label with the x starting at x+criticsSize.width;
//The y will start at y+criticsSize.height-size2.height, so that it will be aligned with the bottom.
//Change these to align it differently.
UILabel *label2 = [[UILabel alloc] initWithFrame:CGRectMake(x+criticsSize.width,y+criticsSize.height-size2.height,size2.width,size2.height)];
[label2 setFont:font2];
[self.view addSubview:label1];
[self.view addSubview:label2];

Resources