Adding two shadows to a UILabel - ios

I have a UILabel that I want to add two shadows.
A black colored shadow, and a white colored one.
One has -1 y-offset, and the other has 1 y-offset.
- (void)layoutSubviews{
[super layoutSubviews];
self.sectionTitleLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
self.sectionTitleLabel.layer.shadowRadius = 0.0f;
self.sectionTitleLabel.layer.shadowOpacity = .2;
self.sectionTitleLabel.layer.shadowOffset = CGSizeMake(0.f, -1.f);
CALayer *blackShadow = [[CALayer alloc] initWithLayer:self.sectionTitleLabel.layer];
blackShadow.shadowColor = [[UIColor blackColor] CGColor];
blackShadow.shadowRadius = 0.0f;
blackShadow.shadowOpacity = .4;
blackShadow.shadowOffset = CGSizeMake(0.f, 1.f);
[self.sectionTitleLabel.layer addSublayer:blackShadow];
self.sectionTitleLabel.layer.masksToBounds = NO;
}
With this the white shadow appears, but the black one does not.

I don't understand what do you mean by "two shadows to a UILabel" but I hope I can help. If on this picture you can see what you want, I will be happy :)
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableAttributedString* attString = [[NSMutableAttributedString alloc] initWithString:self.custLabel.text];
NSRange range = NSMakeRange(0, [attString length]);
[attString addAttribute:NSFontAttributeName value:self.custLabel.font range:range];
[attString addAttribute:NSForegroundColorAttributeName value:self.custLabel.textColor range:range];
NSShadow* shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor whiteColor];
shadow.shadowOffset = CGSizeMake(0.0f, 1.0f);
[attString addAttribute:NSShadowAttributeName value:shadow range:range];
self.custLabel.attributedText = attString;
[self nextShadow];
}
-(void)nextShadow
{
self.custLabel.layer.masksToBounds = NO;
self.custLabel.layer.cornerRadius = 5;
self.custLabel.layer.shadowOffset = CGSizeMake(3, 0);
self.custLabel.layer.shadowRadius = 5;
self.custLabel.layer.shadowOpacity = 1.5;
}
I'd try to use
- (void)addAttributes:(NSDictionary *)attrs range:(NSRange)range;
But you can't use 2 shadow Attributes, only one. And you can customize
-(void)nextShadow
method to create good solution, for example
-(void)nextShadow
{
self.custLabel.layer.masksToBounds = NO;
self.custLabel.layer.cornerRadius = 1;
self.custLabel.layer.shadowOffset = CGSizeMake(1, 0);
self.custLabel.layer.shadowRadius = 1;
self.custLabel.layer.shadowOpacity = 1.5;
}
If you adjust values in -(void)nextShadow you can get what you want.

Related

UILabel Pixelated on Zoom in iOS App

I have a UILabel which added in UIView and this view add as subview of UIScrollViewand zooming is enabled. Working every thing fine but when I zoom in then UILabel and other properties too and this look quite odd.I also added following code for flexible size.
userResizableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
userResizableView.autoresizesSubviews = YES;
Above View is `UIView Type.
And below is code of Label
UILabel * lbl_FormFieldName = [[UILabel alloc]initWithFrame:CGRectMake(1, 1, rect.size.width, 15)];
lbl_FormFieldName.attributedText = attrText;
// lbl_FormFieldName.text = text;
lbl_FormFieldName.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
lbl_FormFieldName.textColor = [UIColor blackColor];
lbl_FormFieldName.backgroundColor = [UIColor clearColor];
lbl_FormFieldName.font = customFont;
lbl_FormFieldName.numberOfLines = 0;
lbl_FormFieldName.baselineAdjustment = UIBaselineAdjustmentAlignBaselines; // or UIBaselineAdjustmentAlignCenters, or UIBaselineAdjustmentNone
lbl_FormFieldName.clipsToBounds = YES;
lbl_FormFieldName.textAlignment = NSTextAlignmentCenter;
Kindly give me any suggestion how to make good. Looking for suggestion.
Thanks
Maybe the frame label is using floating numbers. Try this to force integers value for your frame:
[label setFrame:CGRectIntegral(label.frame)];
As per my requirement I have added pinch gesture on uilabel like this :
1. Add this line before implementation.
CG_INLINE CGRect CGRectScale(CGRect rect, CGFloat wScale, CGFloat hScale)
{
return CGRectMake(rect.origin.x * wScale, rect.origin.y * hScale, rect.size.width * wScale, rect.size.height * hScale);
}
2. Add gesture on label
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(viewDidPinch:)];
pinch.delegate =self;
[self addGestureRecognizer:pinch];
3. Add method in your file. Add scrollview bounds instead of self.bounds as I have different scenario in my case.
- (void)viewDidPinch:(UIPinchGestureRecognizer*)sender
{
CGFloat scale = sender.scale;
CGRect scaleRect = CGRectScale(self.bounds, scale, scale);
if (scaleRect.size.width >= 5 && scaleRect.size.height >= 5) {
[self._label setAttributedText:[self getScaledStringFrom:self._label.attributedText withScale:scale]];
[self._label setFrame:self.bounds];
}
sender.scale=1.0;
}
4. Rewrite text with new scale
- (NSMutableAttributedString*) getScaledStringFrom:(NSMutableAttributedString*)string withScale:(CGFloat)scale
{
[string beginEditing];
[string enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, string.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
if (value) {
UIFont *oldFont = (UIFont *)value;
UIFont *newFont = [oldFont fontWithSize:oldFont.pointSize * scale];
[string removeAttribute:NSFontAttributeName range:range];
[string addAttribute:NSFontAttributeName value:newFont range:range];
}
}];
[string endEditing];
return string;
}

iOS 6 vs iOS 7 drawInRect different result

I am trying to draw a 'wall item' for an iOS app, the problem is when I try to update the code from iOS 6 to iOS 7 (the method is deprecated in iOS 7 so I'm trying to get it up to date)
I attached a picture with the visual result in iOS 6 vs result in iOS 7.
I am new to iOS development so maybe I am missing something.
this part is called in init and in layoutSubviews:
if (_title != nil) {
//
CGFloat flTitleH = MIN(self.rcItem.size.height, MAX(self.rcItem.size.height / 3, 20));
CGFloat flTitleW = self.rcItem.size.width - (2 * _flTitlePadding);
//
CGSize szTitleBoxStart = CGSizeMake(flTitleW, flTitleH);
CGSize szTitleBox;
if (isSystemVersionLessThan_7_0) {
szTitleBox = [self.title sizeWithFont:self.titleFont
constrainedToSize:szTitleBoxStart
lineBreakMode:NSLineBreakByTruncatingTail];
} else {
NSMutableParagraphStyle *paragraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
szTitleBox = [self.title boundingRectWithSize:szTitleBoxStart
options:NSStringDrawingUsesLineFragmentOrigin
attributes:[NSDictionary dictionaryWithObjectsAndKeys:
self.titleFont, NSFontAttributeName,
paragraphStyle, NSParagraphStyleAttributeName,
nil]
context:nil].size;
}
//
CGFloat flTitleNewH = szTitleBox.height + 2 * _flTitlePadding;
self.rcTitle = CGRectMake(self.rcItem.origin.x,
self.rcItem.origin.y + self.rcItem.size.height - flTitleNewH,
self.rcItem.size.width,
flTitleNewH);
}
//
if (_details != nil) {
CGSize szDetailsBox;
if (isSystemVersionLessThan_7_0) {
szDetailsBox = [self.details sizeWithFont:self.detailsFont];
} else {
szDetailsBox = [self.details sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
self.detailsFont, NSFontAttributeName,
nil]];
}
//
CGFloat flDetailsNewH = szDetailsBox.height + _flTitlePadding;
self.rcDetails = CGRectMake(self.rcItem.origin.x,
self.rcItem.origin.y + self.rcItem.size.height - (self.rcTitle.size.height + flDetailsNewH),
self.rcItem.size.width,
flDetailsNewH);
}
//
this code is called in drawRect:
// draw title
if (_title != nil) {
CGContextSaveGState(ctx);
CGRect rcTitleBox = CGRectInset(self.rcTitle, _flTitlePadding, _flTitlePadding);
// draw title background
CGContextSaveGState(ctx);
CGContextSetAlpha(ctx, 0.5);
CGContextSetFillColorWithColor(ctx, [titleBkColor CGColor]);
CGContextFillRect(ctx, self.rcTitle);
// draw title text
CGContextSetAlpha(ctx, 1.0);
CGContextSetFillColorWithColor(ctx, [titleColor CGColor]);
if (isSystemVersionLessThan_7_0) {
[_title drawInRect:rcTitleBox withFont:self.titleFont lineBreakMode:NSLineBreakByTruncatingTail alignment:NSTextAlignmentLeft];
} else {
NSMutableParagraphStyle *paragraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
paragraphStyle.alignment = NSTextAlignmentLeft;
[_title drawInRect:rcTitleBox withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
self.titleFont, NSFontAttributeName,
titleColor, NSForegroundColorAttributeName,
paragraphStyle, NSParagraphStyleAttributeName,
nil]];
}
//
CGContextRestoreGState(ctx);
}
// draw details
if (_details != nil) {
CGContextSaveGState(ctx);
CGRect rcDetailsBox = CGRectInset(self.rcDetails, _flTitlePadding, _flTitlePadding);
// draw title background
CGContextSaveGState(ctx);
CGContextSetAlpha(ctx, 0.5);
CGContextSetFillColorWithColor(ctx, [titleBkColor CGColor]);
CGContextFillRect(ctx, self.rcDetails);
// draw title text
CGContextSetAlpha(ctx, 1.0);
CGContextSetFillColorWithColor(ctx, [titleColor CGColor]);
if (isSystemVersionLessThan_7_0) {
[_details drawInRect:rcDetailsBox withFont:self.detailsFont lineBreakMode:NSLineBreakByTruncatingTail alignment:NSTextAlignmentLeft];
} else {
NSMutableParagraphStyle *paragraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
paragraphStyle.alignment = NSTextAlignmentLeft;
[_details drawInRect:rcDetailsBox withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
self.detailsFont, NSFontAttributeName,
titleColor, NSForegroundColorAttributeName,
paragraphStyle, NSParagraphStyleAttributeName,
nil]];
}
In this example, _title is equal to "Jurubita, KPMG..." and _details is equal to "Friday, ZF24"
iOS6:
iOS7:
I don't know why the text and font are different, the pictures speak for themselves. Also 'y' in 'Friday' is not displayed properly.
What is different between the two methods?

Draw text outside of CGRect.

I am using Apple's Sample Code TheElements for this question. How would I go about drawing text outside of the elementSymbolRectangle. For example I would like to display the Elements Name, but I need it to be outside of the elementSymbolRectangle. I am new to programming and would appreciate any help.
Thanks
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setAutoresizesSubviews:YES];
[self setupUserInterface];
// set the background color of the view to clearn
self.backgroundColor=[UIColor clearColor];
}
return self;
}
- (void)jumpToWikipedia:(id)sender {
// create the string that points to the correct Wikipedia page for the element name
NSString *wikiPageString = [NSString stringWithFormat:#"http://en.wikipedia.org/wiki/%#", self.element.name];
if (![[UIApplication sharedApplication] openURL:[NSURL URLWithString:wikiPageString]])
{
// there was an error trying to open the URL. for the moment we'll simply ignore it.
}
}
- (void)drawRect:(CGRect)rect {
// get the background image for the state of the element
// position it appropriately and draw the image
//
UIImage *backgroundImage = [self.element stateImageForAtomicElementView];
CGRect elementSymbolRectangle = CGRectMake(0, 0, [backgroundImage size].width, [backgroundImage size].height);
[backgroundImage drawInRect:elementSymbolRectangle];
// all the text is drawn in white
[[UIColor whiteColor] set];
// draw the element number
UIFont *font = [UIFont boldSystemFontOfSize:32];
CGPoint point = CGPointMake(10,5);
[[NSString stringWithFormat:#"%#", self.element.atomicNumber] drawAtPoint:point withFont:font];
// draw the element symbol
CGSize stringSize = [self.element.symbol sizeWithFont:font];
point = CGPointMake((self.bounds.size.width-stringSize.width-10),5);
[self.element.symbol drawAtPoint:point withFont:font];
This solved my problem.
UILabel *scoreLabel = [ [UILabel alloc ] initWithFrame:CGRectMake((self.bounds.size.width / 2), -50.0, 100.0, 100.0) ];
scoreLabel.textAlignment = UITextAlignmentCenter;
scoreLabel.textColor = [UIColor whiteColor];
scoreLabel.backgroundColor = [UIColor blackColor];
scoreLabel.font = [UIFont fontWithName:#"Arial Rounded MT Bold" size:(36.0)];
[self addSubview:scoreLabel];
scoreLabel.text = [NSString stringWithFormat: #"Test"];

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

Underline text in UIlabel

How can I underline a text that could be multiple lines of string?
I find some people suggest UIWebView, but it is obviously too heavy a class for just text rendering.
My thoughts was to figure out the start point and length of each string in each line.
And draw a line under it accordingly.
I meet problems at how to figure out the length and start point for the string.
I tried to use -[UILabel textRectForBounds:limitedToNumberOfLines:], this should be the drawing bounding rect for the text right?
Then I have to work on the alignment?
How can I get the start point of each line when it is center-justified and right justified?
You may subclass from UILabel and override drawRect method:
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(ctx, 207.0f/255.0f, 91.0f/255.0f, 44.0f/255.0f, 1.0f); // RGBA
CGContextSetLineWidth(ctx, 1.0f);
CGContextMoveToPoint(ctx, 0, self.bounds.size.height - 1);
CGContextAddLineToPoint(ctx, self.bounds.size.width, self.bounds.size.height - 1);
CGContextStrokePath(ctx);
[super drawRect:rect];
}
UPD:
As of iOS 6 Apple added NSAttributedString support for UILabel, so now it's much easier and works for multiple lines:
NSDictionary *underlineAttribute = #{NSUnderlineStyleAttributeName: #(NSUnderlineStyleSingle)};
myLabel.attributedText = [[NSAttributedString alloc] initWithString:#"Test string"
attributes:underlineAttribute];
If you still wish to support iOS 4 and iOS 5, I'd recommend to use TTTAttributedLabel rather than underline label manually. However if you need to underline one-line UILabel and don't want to use third-party components, code above would still do the trick.
In Swift:
let underlineAttriString = NSAttributedString(string: "attriString",
attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue])
label.attributedText = underlineAttriString
This is what i did. It works like butter.
1) Add CoreText.framework to your Frameworks.
2) import <CoreText/CoreText.h> in the class where you need underlined label.
3) Write the following code.
NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] initWithString:#"My Messages"];
[attString addAttribute:(NSString*)kCTUnderlineStyleAttributeName
value:[NSNumber numberWithInt:kCTUnderlineStyleSingle]
range:(NSRange){0,[attString length]}];
self.myMsgLBL.attributedText = attString;
self.myMsgLBL.textColor = [UIColor whiteColor];
Use an attribute string:
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:#"Your String"]
[attrString addAttribute:(NSString*)kCTUnderlineStyleAttributeName
value:[NSNumber numberWithInt:kCTUnderlineStyleSingle]
range:(NSRange){0,[attrString length]}];
And then override the label - (void)drawTextInRect:(CGRect)aRect and render the text in something like:
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrString);
drawingRect = self.bounds;
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, drawingRect);
textFrame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0), path, NULL);
CGPathRelease(path);
CFRelease(framesetter);
CTFrameDraw(textFrame, ctx);
CGContextRestoreGState(ctx);
Or better yet instead of overriding just use the OHAttributedLabel created by Olivier Halligon
I've combined some of provided answers, to create better (at least for my requirements) UILabel subclass, which supports:
multiline text with various label bounds (text can be in the middle of label frame, or accurate size)
underline
strikeout
underline/strikeout line offset
text alignment
different font sizes
https://github.com/GuntisTreulands/UnderLineLabel
People, who do not want to subclass the view (UILabel/UIButton) etc...
'forgetButton' can be replace by any lable too.
-(void) drawUnderlinedLabel {
NSString *string = [forgetButton titleForState:UIControlStateNormal];
CGSize stringSize = [string sizeWithFont:forgetButton.titleLabel.font];
CGRect buttonFrame = forgetButton.frame;
CGRect labelFrame = CGRectMake(buttonFrame.origin.x + buttonFrame.size.width - stringSize.width,
buttonFrame.origin.y + stringSize.height + 1 ,
stringSize.width, 2);
UILabel *lineLabel = [[UILabel alloc] initWithFrame:labelFrame];
lineLabel.backgroundColor = [UIColor blackColor];
//[forgetButton addSubview:lineLabel];
[self.view addSubview:lineLabel];
}
NSString *tem =self.detailCustomerCRMCaseLabel.text;
if (tem != nil && ![tem isEqualToString:#""]) {
NSMutableAttributedString *temString=[[NSMutableAttributedString alloc]initWithString:tem];
[temString addAttribute:NSUnderlineStyleAttributeName
value:[NSNumber numberWithInt:1]
range:(NSRange){0,[temString length]}];
self.detailCustomerCRMCaseLabel.attributedText = temString;
}
Another solution could be (since iOS 7) given a negative value to NSBaselineOffsetAttributeName, for example your NSAttributedString could be:
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:#"my text goes here'
attributes:#{NSFontAttributeName: [UIFont fontWithName:#"Helvetica-Regular" size:12],
NSForegroundColorAttributeName: [UIColor blackColor],
NSUnderlineStyleAttributeName: #(NSUnderlineStyleSingle), NSBaselineOffsetAttributeName: #(-3)}];
Hope this will help ;-)
NSMutableAttributedString *text = [self.myUILabel.attributedText mutableCopy];
[text addAttribute:NSUnderlineStyleAttributeName value:#(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)];
self.myUILabel.attributedText = text;
You can create a custom label with name UnderlinedLabel and edit drawRect function.
#import "UnderlinedLabel.h"
#implementation UnderlinedLabel
- (void)drawRect:(CGRect)rect
{
NSString *normalTex = self.text;
NSDictionary *underlineAttribute = #{NSUnderlineStyleAttributeName: #(NSUnderlineStyleSingle)};
self.attributedText = [[NSAttributedString alloc] initWithString:normalTex
attributes:underlineAttribute];
[super drawRect:rect];
}
Here is the easiest solution which works for me without writing additional codes.
// To underline text in UILable
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:#"Type your text here"];
[text addAttribute:NSUnderlineStyleAttributeName value:#(NSUnderlineStyleSingle) range:NSMakeRange(0, text.length)];
lblText.attributedText = text;
Sometimes we developer stuck in small designing part of any UI screen. One of the most irritating requirement is under line text. Don’t worry here is the solution.
Underlining a text in a UILabel using Objective C
UILabel *label=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
label.backgroundColor=[UIColor lightGrayColor];
NSMutableAttributedString *attributedString;
attributedString = [[NSMutableAttributedString alloc] initWithString:#"Apply Underlining"];
[attributedString addAttribute:NSUnderlineStyleAttributeName value:#1 range:NSMakeRange(0,
[attributedString length])];
[label setAttributedText:attributedString];
Underlining a text in UILabel using Swift
label.backgroundColor = .lightGray
let attributedString = NSMutableAttributedString.init(string: "Apply UnderLining")
attributedString.addAttribute(NSUnderlineStyleAttributeName, value: 1, range:
NSRange.init(location: 0, length: attributedString.length))
label.attributedText = attributedString
An enhanced version of the code of Kovpas (color and line size)
#implementation UILabelUnderlined
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
const CGFloat* colors = CGColorGetComponents(self.textColor.CGColor);
CGContextSetRGBStrokeColor(ctx, colors[0], colors[1], colors[2], 1.0); // RGBA
CGContextSetLineWidth(ctx, 1.0f);
CGSize tmpSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(200, 9999)];
CGContextMoveToPoint(ctx, 0, self.bounds.size.height - 1);
CGContextAddLineToPoint(ctx, tmpSize.width, self.bounds.size.height - 1);
CGContextStrokePath(ctx);
[super drawRect:rect];
}
#end
I have Created for multiline uilabel with underline :
For Font size 8 to 13 set int lineHeight = self.font.pointSize+3;
For font size 14 to 20 set int lineHeight = self.font.pointSize+4;
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
const CGFloat* colors = CGColorGetComponents(self.textColor.CGColor);
CGContextSetRGBStrokeColor(ctx, colors[0], colors[1], colors[2], 1.0); // RGBA
CGContextSetLineWidth(ctx, 1.0f);
CGSize tmpSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(self.frame.size.width, 9999)];
int height = tmpSize.height;
int lineHeight = self.font.pointSize+4;
int maxCount = height/lineHeight;
float totalWidth = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(1000, 9999)].width;
for(int i=1;i<=maxCount;i++)
{
float width=0.0;
if((i*self.frame.size.width-totalWidth)<=0)
width = self.frame.size.width;
else
width = self.frame.size.width - (i* self.frame.size.width - totalWidth);
CGContextMoveToPoint(ctx, 0, lineHeight*i-1);
CGContextAddLineToPoint(ctx, width, lineHeight*i-1);
}
CGContextStrokePath(ctx);
[super drawRect:rect];
}
Swift 4.1 ver:
let underlineAttriString = NSAttributedString(string:"attriString", attributes:
[NSAttributedStringKey.underlineStyle: NSUnderlineStyle.styleSingle.rawValue])
label.attributedText = underlineAttriString
As kovpas has shown you can use the bounding box in most cases, although it is not always guaranteed that the bounding box will fit neatly around the text. A box with a height of 50 and font size of 12 may not give the results you want depending on the UILabel configuration.
Query the UIString within the UILabel to determine its exact metrics and use these to better place your underline regardless of the enclosing bounding box or frame using the drawing code already provided by kovpas.
You should also look at UIFont's "leading" property that gives the distance between baselines based on a particular font. The baseline is where you would want your underline to be drawn.
Look up the UIKit additions to NSString:
(CGSize)sizeWithFont:(UIFont *)font
//Returns the size of the string if it were to be rendered with the specified font on a single line.
(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
// Returns the size of the string if it were rendered and constrained to the specified size.
(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
//Returns the size of the string if it were rendered with the specified constraints.
I use an open source line view and just added it to the button subviews:
UILabel *label = termsButton.titleLabel;
CGRect frame = label.frame;
frame.origin.y += frame.size.height - 1;
frame.size.height = 1;
SSLineView *line = [[SSLineView alloc] initWithFrame:frame];
line.lineColor = [UIColor lightGrayColor];
[termsButton addSubview:line];
This was inspired by Karim above.
Based on Kovpas & Damien Praca's Answers, here is an implementation of UILabelUnderligned which also support textAlignemnt.
#import <UIKit/UIKit.h>
#interface UILabelUnderlined : UILabel
#end
and the implementation:
#import "UILabelUnderlined.h"
#implementation DKUILabel
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
const CGFloat* colors = CGColorGetComponents(self.textColor.CGColor);
CGContextSetRGBStrokeColor(ctx, colors[0], colors[1], colors[2], 1.0); // RGBA
CGContextSetLineWidth(ctx, 1.0f);
CGSize textSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(200, 9999)];
// handle textAlignement
int alignementXOffset = 0;
switch (self.textAlignment) {
case UITextAlignmentLeft:
break;
case UITextAlignmentCenter:
alignementXOffset = (self.frame.size.width - textSize.width)/2;
break;
case UITextAlignmentRight:
alignementXOffset = self.frame.size.width - textSize.width;
break;
}
CGContextMoveToPoint(ctx, alignementXOffset, self.bounds.size.height - 1);
CGContextAddLineToPoint(ctx, alignementXOffset+textSize.width, self.bounds.size.height - 1);
CGContextStrokePath(ctx);
[super drawRect:rect];
}
#end
Here's another, simpler solution (underline's width is not most accurate but it was good enough for me)
I have a UIView (_view_underline) that has White background, height of 1 pixel and I update its width everytime I update the text
// It's a shame you have to do custom stuff to underline text
- (void) underline {
float width = [[_txt_title text] length] * 10.0f;
CGRect prev_frame = [_view_underline frame];
prev_frame.size.width = width;
[_view_underline setFrame:prev_frame];
}
NSUnderlineStyleAttributeName which takes an NSNumber (where 0 is no underline) can be added to an attribute dictionary.
I don't know if this is any easier. But, it was easier for my purposes.
NSDictionary *attributes;
attributes = #{NSFontAttributeName:font, NSParagraphStyleAttributeName: style, NSUnderlineStyleAttributeName:[NSNumber numberWithInteger:1]};
[text drawInRect:CGRectMake(self.contentRect.origin.x, currentY, maximumSize.width, textRect.size.height) withAttributes:attributes];
You can use this my custom label!
You can also use interface builder to set
import UIKit
class YHYAttributedLabel : UILabel{
#IBInspectable
var underlineText : String = ""{
didSet{
self.attributedText = NSAttributedString(string: underlineText,
attributes: [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue])
}
}
}

Resources