NSAttributedString: underline is not applied - ios

I'm trying to add underline style for UITextView and it's not applied. If i use "shadow" (uncomment shadow styling and comment underline styling) i can see it, but no underline is applied for some reason. I use "Courier New" font.
- (void) addDiagHighlighting: (NSMutableAttributedString*)attrString start:(int)start end:(int)end severity:(int)severity {
// ignore diags that are out of bounds
if (start > attrString.length || end > attrString.length)
return;
NSRange range = NSMakeRange(start, end - start);
UIColor *diagColor = [self getSeverityColor: severity];
// shadow
// NSShadow *shadow = [[NSShadow alloc] init];
// [shadow setShadowColor: diagColor];
// [shadow setShadowOffset: CGSizeMake (1.0, 1.0)];
// [shadow setShadowBlurRadius: 1.0];
// [attrString addAttribute:NSShadowAttributeName
// value:shadow
// range:range];
// underline
[attrString addAttributes:#{
NSUnderlineColorAttributeName : diagColor, // color
NSUnderlineStyleAttributeName : #(NSUnderlinePatternSolid) // style
}
range:range];
}
i can change adding attributes to adding both shadow and underling and i can see shadow but still no underline:
// shadow + underline
[attrString addAttributes:#{
NSShadowAttributeName : shadow, // shadow
NSUnderlineColorAttributeName : diagColor, // color
NSUnderlineStyleAttributeName : #(NSUnderlinePatternSolid) // style
}
range:range];

You need to OR a NSUnderlinePattern with an NSUnderlineStyle to get it working (see Apple documentation here)
Try this:
[attrString addAttributes:#{
NSShadowAttributeName : shadow, // shadow
NSUnderlineColorAttributeName : diagColor, // color
NSUnderlineStyleAttributeName : #(NSUnderlineStyleSingle | NSUnderlinePatternSolid) // style
}
range:range];
Or with dots...
[attrString addAttributes:#{
NSShadowAttributeName : shadow, // shadow
NSUnderlineColorAttributeName : diagColor, // color
NSUnderlineStyleAttributeName : #(NSUnderlineStyleSingle | NSUnderlinePatternDot) // style
}
range:range];

The Apple Developer Documentation states about NSUnderlineStyle:
The style, pattern, and optionally by-word mask are OR'd together to produce the value for underlineStyle and strikethroughStyle.
Therefore, with Swift 5 and iOS 12.3, you can use the bitwise OR operator (|) to set a style and a pattern together for NSAttributedString.Key.underlineStyle attribute.
The following Playground sample code shows how to set both NSUnderlineStyle.thick and NSUnderlineStyle.patternDot attributes for a NSAttributedString instance:
import UIKit
import PlaygroundSupport
let attributes = [NSAttributedString.Key.underlineStyle : (NSUnderlineStyle.thick.rawValue | NSUnderlineStyle.patternDot.rawValue)]
let attributedString = NSAttributedString(string: "Some text", attributes: attributes)
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 40))
label.backgroundColor = .white
label.attributedText = attributedString
PlaygroundPage.current.liveView = label

Related

Is there no way to decrease line spacing on a UILabel's text? [duplicate]

I want to have two lines of text appear really close together (small line spacing) for a button. I have the following code:
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:#"50 WPM"];
NSMutableParagraphStyle *paragrapStyle = [[NSMutableParagraphStyle alloc] init];
paragrapStyle.alignment = NSTextAlignmentCenter;
paragrapStyle.lineSpacing = -10;
[string addAttribute:NSParagraphStyleAttributeName value:paragrapStyle range:NSMakeRange(0, string.length)];
UIFont *font1 = [UIFont systemFontOfSize:22.0];
[string addAttribute:NSFontAttributeName value:font1 range:NSMakeRange(0, string.length - 4)];
UIFont *font = [UIFont systemFontOfSize:15.0];
[string addAttribute:NSFontAttributeName value:font range:NSMakeRange(string.length - 3, 3)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(0, string.length)];
[self.button setAttributedTitle:string forState:UIControlStateNormal];
But as linespacing can't be negative, it doesn't get nearly as close as I'd like it to be. It looks like this:
Is there any way to get them closer?
Well if you have an attribute string then everything should be possible. :) You just have to look more.
- (void)setMinimumLineHeight:(CGFloat)aFloat
- (void)setMaximumLineHeight:(CGFloat)aFloat
Try
[paragraphStyle setLineSpacing:0.0f];
[paragraphStyle setMaximumLineHeight:7.0f];
You will realise that maximumLineHeight is not maximumLineSpacing. ^^
This for example is with setMaximumLineHeight:12];
Here a little extension in Swift3 which supports negative lineSpacing
extension UILabel {
func set(lineSpacing: CGFloat, textAlignment: NSTextAlignment = NSTextAlignment.center) {
if let text = self.text {
let paragraphStyle = NSMutableParagraphStyle()
if lineSpacing < 0 {
paragraphStyle.lineSpacing = 0
paragraphStyle.maximumLineHeight = self.font.pointSize + lineSpacing
} else {
paragraphStyle.lineSpacing = lineSpacing
}
let attrString = NSMutableAttributedString(string: text)
attrString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
self.attributedText = attrString
self.textAlignment = textAlignment
}
}
}
I would suggest reading up on TextKit that was introduced in iOS7. I do not have much experience from it, but I do know that it gives you a lot of possibilities when it comes to attributing your texts.
In Swift 3, you can achieve this by :
let paragraph = NSMutableParagraphStyle()
paragraph.lineSpacing = 0
paragraph.maximumLineHeight = 20.
Keep the lineSpacing = 0. You can adjust the maximumLineHeight to make it closer or to increase the spacing.
How about subclassing UIButton, and add 2 UILabels to the buttons view that are close together. Create properties for the labels and set approrpietly:
CustomButton *btn = [CustomButton new];
btn.textLine1 = #"Top";
btn.textLine2 = #"Bottom";
The only problem doing it this way is you will need to handle the text color when the state changes yourself.

Underline UIlabel so the underlining always reaches the bounds

What I want to achieve is to have UILabel underlined but in a specific way.
I know how to make UILabel underlined, but since this is going to be a dynamic text, I don't know how long it will be.
Anytime the label enters a new line, I'd like to make the underlining align with the one above regardless of the text length.
I sketched it up to give you a better notion of what I actually try to achieve:
What is your opinion, how to approach such problem?
Should I add the white line as UIView anytime text skips to another line?
Or maybe add some whitespace in code when the text lengths is shorter than bounds of current line?
first you need to set text for you label then call this method :
- (void)underlineLabel:(UILabel*)lbl {
if (![lbl respondsToSelector:#selector(setAttributedText:)]) {
return;
}
NSMutableAttributedString *attributedText;
if (!lbl.attributedText) {
attributedText = [[NSMutableAttributedString alloc] initWithString:lbl.text];
} else {
attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:lbl.attributedText];
}
long len = [lbl.text length];
[attributedText addAttribute:NSUnderlineColorAttributeName value:[UIColor grayColor] range:NSMakeRange(0,len)];
[attributedText addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:1] range:NSMakeRange(0, len)];//Underline color
lbl.attributedText = attributedText;
}
func underlineLabel(label: UILabel) {
if !lbl.respondsToSelector("setAttributedText:") {
return
}
var attributedText = NSMutableAttributedString()
if !(lbl.attributedText != nil) {
attributedText = NSMutableAttributedString(string:label.text!)
}
else {
attributedText = NSMutableAttributedString(attributedString: label.attributedText!)
}
let str = label.text;
let len = str?.characters.count;
attributedText.addAttribute(NSUnderlineColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(0, len!))
attributedText.addAttribute(NSUnderlineStyleAttributeName , value:1, range: NSMakeRange(0, len!))
//Underline color
lbl.attributedText = attributedText
}
I have came up with solution with custom label class and override drawRect Method in that custom class of UIlabel.
CustomLabel.h
#import <UIKit/UIKit.h>
#interface CustomLabel : UILabel
#end
CustomLabel.m
#import "CustomLabel.h"
#implementation CustomLabel
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, 1.0f);
float Left = self.center.x - self.frame.size.width/2.0;
float Right = self.center.x + self.frame.size.width/2.0;
CGContextMoveToPoint(ctx, Left, self.bounds.size.height - 1);
CGContextAddLineToPoint(ctx, Right, self.bounds.size.height - 1);
CGContextStrokePath(ctx);
[super drawRect:rect];
}
#end
In Your Class Just import this custom Class.
#import "CustomLabel.h"
////// you can create labels now which are having underline to bounds.
-(void)CreateCustomLabel
{
CustomLabel *custom = [[CustomLabel alloc] initWithFrame:CGRectMake(0, 150, SCREEN_WIDTH-40, 50)];
custom.text = #"Your Text Here";
custom.backgroundColor = [UIColor redColor];
[self.view addSubview:custom];
}

Two colors for UILabel TEXT

I want to set two colors for UILabel's text. I tried TTTRegexAttributedLabel, but it is throwing unknown type error.
I tried following code too. But it is crashing at settext.
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:#"Hello. That is a test attributed string."];
[str addAttribute: #"Hello" value:[UIColor yellowColor] range:NSMakeRange(3,5)];
[str addAttribute:#"That" value:[UIColor greenColor] range:NSMakeRange(10,7)];
[str addAttribute:#"Hello" value:[UIFont fontWithName:#"HelveticaNeue-Bold" size:20.0] range:NSMakeRange(20, 10)];
[syncStatusLabel setText:(NSString *)str];
Is there any other way to set multiple colors for single UILabel text?
you can set text color with pattern image like bellow..
[yourLable setTextColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"yourImageName"]]];
and also set different color with this bellow code.. please check tutorial with detail mate..
NSString *test = #"Hello. That is a test attributed string.";
CFStringRef string = (CFStringRef) test;
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CFAttributedStringReplaceString (attrString,CFRangeMake(0, 0), string);
/*
Note: we could have created CFAttributedStringRef which is non mutable, then we would have to give all its
attributes right when we create it. We can change them if we use mutable form of CFAttributeString.
*/
//Lets choose the colors we want to have in our string
CGColorRef _orange=[UIColor orangeColor].CGColor;
CGColorRef _green=[UIColor greenColor].CGColor;
CGColorRef _red=[UIColor redColor].CGColor;
CGColorRef _blue=[UIColor blueColor].CGColor;
//Lets have our string with first 20 letters as orange
//next 20 letters as green
//next 20 as red
//last remaining as blue
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 20),kCTForegroundColorAttributeName, _orange);
CFAttributedStringSetAttribute(attrString, CFRangeMake(20, 20),kCTForegroundColorAttributeName, _green);
CFAttributedStringSetAttribute(attrString, CFRangeMake(40, 20),kCTForegroundColorAttributeName, _red);
CFAttributedStringSetAttribute(attrString, CFRangeMake(60, _stringLength-61),kCTForegroundColorAttributeName, _blue);
for more information see this tutorial....
coretext-tutorial-for-ios-part
i hope this help you...
NSAttributedString has to be set using UILabel's attributedText property. e.g [syncStatusLabel setAttributedText:str] in your case. Good Luck!
Try this with swift (execute code with following extension)
extension NSMutableAttributedString {
func setColorForText(textToFind: String, withColor color: UIColor) {
let range: NSRange = self.mutableString.range(of: textToFind, options: .caseInsensitive)
self.addAttribute(NSAttributedStringKey.foregroundColor, value: color, range: range)
}
}
Try an extension with UILabel:
self.view.backgroundColor = UIColor.blue.withAlphaComponent(0.5)
let label = UILabel()
label.frame = CGRect(x: 40, y: 100, width: 280, height: 200)
let stringValue = "Hello. That is a test attributed string." // or direct assign single string value like "firstsecondthird"
label.textColor = UIColor.lightGray
label.numberOfLines = 0
let attributedString: NSMutableAttributedString = NSMutableAttributedString(string: stringValue)
attributedString.setColorForText(textToFind: "Hello", withColor: UIColor.yellow)
attributedString.setColorForText(textToFind: "That", withColor: UIColor.green)
label.font = UIFont.systemFont(ofSize: 26)
label.attributedText = attributedString
self.view.addSubview(label)
Here is result:

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])
}
}
}

iPhone UITextField - Change placeholder text color

I'd like to change the color of the placeholder text I set in my UITextField controls, to make it black.
I'd prefer to do this without using normal text as the placeholder and having to override all the methods to imitate the behaviour of a placeholder.
I believe if I override this method:
- (void)drawPlaceholderInRect:(CGRect)rect
then I should be able to do this. But I'm unsure how to access the actual placeholder object from within this method.
Since the introduction of attributed strings in UIViews in iOS 6, it's possible to assign a color to the placeholder text like this:
if ([textField respondsToSelector:#selector(setAttributedPlaceholder:)]) {
UIColor *color = [UIColor blackColor];
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:placeholderText attributes:#{NSForegroundColorAttributeName: color}];
} else {
NSLog(#"Cannot set placeholder text's color, because deployment target is earlier than iOS 6.0");
// TODO: Add fall-back code to set placeholder color.
}
Easy and pain-free, could be an easy alternative for some.
_placeholderLabel.textColor
Not suggested for production, Apple may reject your submission.
You can override drawPlaceholderInRect:(CGRect)rect as such to manually render the placeholder text:
- (void) drawPlaceholderInRect:(CGRect)rect {
[[UIColor blueColor] setFill];
[[self placeholder] drawInRect:rect withFont:[UIFont systemFontOfSize:16]];
}
This works in Swift <3.0:
myTextField.attributedPlaceholder =
NSAttributedString(string: "placeholder text", attributes: [NSForegroundColorAttributeName : UIColor.redColor()])
Tested in iOS 8.2 and iOS 8.3 beta 4.
Swift 3:
myTextfield.attributedPlaceholder =
NSAttributedString(string: "placeholder text", attributes: [NSForegroundColorAttributeName : UIColor.red])
Swift 4:
myTextfield.attributedPlaceholder =
NSAttributedString(string: "placeholder text", attributes: [NSAttributedStringKey.foregroundColor: UIColor.red])
Swift 4.2:
myTextfield.attributedPlaceholder =
NSAttributedString(string: "placeholder text", attributes: [NSAttributedString.Key.foregroundColor: UIColor.red])
You can Change the Placeholder textcolor to any color which you want by using the below code.
UIColor *color = [UIColor lightTextColor];
YOURTEXTFIELD.attributedPlaceholder = [[NSAttributedString alloc] initWithString:#"PlaceHolder Text" attributes:#{NSForegroundColorAttributeName: color}];
Maybe you want to try this way, but Apple might warn you about accessing private ivar:
[self.myTextField setValue:[UIColor darkGrayColor]
forKeyPath:#"_placeholderLabel.textColor"];
NOTE
This is not working on iOS 7 anymore, according to Martin Alléus.
Swift 3.0 + Storyboard
In order to change placeholder color in storyboard, create an extension with next code. (feel free to update this code, if you think, it can be clearer and safer).
extension UITextField {
#IBInspectable var placeholderColor: UIColor {
get {
guard let currentAttributedPlaceholderColor = attributedPlaceholder?.attribute(NSForegroundColorAttributeName, at: 0, effectiveRange: nil) as? UIColor else { return UIColor.clear }
return currentAttributedPlaceholderColor
}
set {
guard let currentAttributedString = attributedPlaceholder else { return }
let attributes = [NSForegroundColorAttributeName : newValue]
attributedPlaceholder = NSAttributedString(string: currentAttributedString.string, attributes: attributes)
}
}
}
Swift 4 version
extension UITextField {
#IBInspectable var placeholderColor: UIColor {
get {
return attributedPlaceholder?.attribute(.foregroundColor, at: 0, effectiveRange: nil) as? UIColor ?? .clear
}
set {
guard let attributedPlaceholder = attributedPlaceholder else { return }
let attributes: [NSAttributedStringKey: UIColor] = [.foregroundColor: newValue]
self.attributedPlaceholder = NSAttributedString(string: attributedPlaceholder.string, attributes: attributes)
}
}
}
Swift 5 version
extension UITextField {
#IBInspectable var placeholderColor: UIColor {
get {
return attributedPlaceholder?.attribute(.foregroundColor, at: 0, effectiveRange: nil) as? UIColor ?? .clear
}
set {
guard let attributedPlaceholder = attributedPlaceholder else { return }
let attributes: [NSAttributedString.Key: UIColor] = [.foregroundColor: newValue]
self.attributedPlaceholder = NSAttributedString(string: attributedPlaceholder.string, attributes: attributes)
}
}
}
In Swift:
if let placeholder = yourTextField.placeholder {
yourTextField.attributedPlaceholder = NSAttributedString(string:placeholder,
attributes: [NSForegroundColorAttributeName: UIColor.blackColor()])
}
In Swift 4.0:
if let placeholder = yourTextField.placeholder {
yourTextField.attributedPlaceholder = NSAttributedString(string:placeholder,
attributes: [NSAttributedStringKey.foregroundColor: UIColor.black])
}
The following only with iOS6+ (as indicated in Alexander W's comment):
UIColor *color = [UIColor grayColor];
nameText.attributedPlaceholder =
[[NSAttributedString alloc]
initWithString:#"Full Name"
attributes:#{NSForegroundColorAttributeName:color}];
I had already faced this issue. In my case below code is correct.
Objective C
[textField setValue:[UIColor whiteColor] forKeyPath:#"_placeholderLabel.textColor"];
For Swift 4.X
tf_mobile.setValue(UIColor.white, forKeyPath: "_placeholderLabel.textColor")
For iOS 13 Swift Code
tf_mobile.attributedPlaceholder = NSAttributedString(string:"PlaceHolder Text", attributes: [NSAttributedString.Key.foregroundColor: UIColor.red])
You can also use below code for iOS 13
let iVar = class_getInstanceVariable(UITextField.self, "_placeholderLabel")!
let placeholderLabel = object_getIvar(tf_mobile, iVar) as! UILabel
placeholderLabel.textColor = .red
Hope, this may help you.
With this we can change the color of textfield's placeholder text in iOS
[self.userNameTxt setValue:[UIColor colorWithRed:41.0/255.0 green:91.0/255.0 blue:106.0/255.0 alpha:1.0] forKeyPath:#"_placeholderLabel.textColor"];
in swift 3.X
textField.attributedPlaceholder = NSAttributedString(string: "placeholder text", attributes:[NSForegroundColorAttributeName: UIColor.black])
in swift 5
textField.attributedPlaceholder = NSAttributedString(string: "placeholder text", attributes: [NSAttributedString.Key.foregroundColor : UIColor.black])
Why don't you just use UIAppearance method:
[[UILabel appearanceWhenContainedIn:[UITextField class], nil] setTextColor:[UIColor whateverColorYouNeed]];
Also in your storyboard, without single line of code
For iOS 6.0 +
[textfield setValue:your_color forKeyPath:#"_placeholderLabel.textColor"];
Hope it helps.
Note: Apple may reject (0.01% chances) your app as we are accessing private API. I am using this in all my projects since two years, but Apple didn't ask for this.
For Xamarin.iOS developers, I found it from this document
https://developer.xamarin.com/api/type/Foundation.NSAttributedString/
textField.AttributedPlaceholder = new NSAttributedString ("Hello, world",new UIStringAttributes () { ForegroundColor = UIColor.Red });
Swift version. Probably it would help someone.
class TextField: UITextField {
override var placeholder: String? {
didSet {
let placeholderString = NSAttributedString(string: placeholder!, attributes: [NSForegroundColorAttributeName: UIColor.whiteColor()])
self.attributedPlaceholder = placeholderString
}
}
}
iOS 6 and later offers attributedPlaceholder on UITextField.
iOS 3.2 and later offers setAttributes:range: on NSMutableAttributedString.
You can do the following:
NSMutableAttributedString *ms = [[NSMutableAttributedString alloc] initWithString:self.yourInput.placeholder];
UIFont *placeholderFont = self.yourInput.font;
NSRange fullRange = NSMakeRange(0, ms.length);
NSDictionary *newProps = #{NSForegroundColorAttributeName:[UIColor yourColor], NSFontAttributeName:placeholderFont};
[ms setAttributes:newProps range:fullRange];
self.yourInput.attributedPlaceholder = ms;
To handle both vertical and horizontal alignment as well as color of placeholder in iOS7. drawInRect and drawAtPoint no longer use current context fillColor.
https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/CustomTextProcessing/CustomTextProcessing.html
Obj-C
#interface CustomPlaceHolderTextColorTextField : UITextField
#end
#implementation CustomPlaceHolderTextColorTextField : UITextField
-(void) drawPlaceholderInRect:(CGRect)rect {
if (self.placeholder) {
// color of placeholder text
UIColor *placeHolderTextColor = [UIColor redColor];
CGSize drawSize = [self.placeholder sizeWithAttributes:[NSDictionary dictionaryWithObject:self.font forKey:NSFontAttributeName]];
CGRect drawRect = rect;
// verticially align text
drawRect.origin.y = (rect.size.height - drawSize.height) * 0.5;
// set alignment
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.alignment = self.textAlignment;
// dictionary of attributes, font, paragraphstyle, and color
NSDictionary *drawAttributes = #{NSFontAttributeName: self.font,
NSParagraphStyleAttributeName : paragraphStyle,
NSForegroundColorAttributeName : placeHolderTextColor};
// draw
[self.placeholder drawInRect:drawRect withAttributes:drawAttributes];
}
}
#end
This solution for Swift 4.1
textName.attributedPlaceholder = NSAttributedString(string: textName.placeholder!, attributes: [NSAttributedStringKey.foregroundColor : UIColor.red])
Categories FTW. Could be optimized to check for effective color change.
#import <UIKit/UIKit.h>
#interface UITextField (OPConvenience)
#property (strong, nonatomic) UIColor* placeholderColor;
#end
#import "UITextField+OPConvenience.h"
#implementation UITextField (OPConvenience)
- (void) setPlaceholderColor: (UIColor*) color {
if (color) {
NSMutableAttributedString* attrString = [self.attributedPlaceholder mutableCopy];
[attrString setAttributes: #{NSForegroundColorAttributeName: color} range: NSMakeRange(0, attrString.length)];
self.attributedPlaceholder = attrString;
}
}
- (UIColor*) placeholderColor {
return [self.attributedPlaceholder attribute: NSForegroundColorAttributeName atIndex: 0 effectiveRange: NULL];
}
#end
Swift 5 WITH CAVEAT.
let attributes = [ NSAttributedString.Key.foregroundColor: UIColor.someColor ]
let placeHolderString = NSAttributedString(string: "DON'T_DELETE", attributes: attributes)
txtField.attributedPlaceholder = placeHolderString
The caveat being that you MUST enter a non-empty String where "DON'T_DELETE" is, even if that string is set in code elsewhere. Might save you five minutes of head-sctratching.
if subclassing you MUST do it in layoutSubviews (not in init)
strangely you do NOT have to clear the normal placeholder. it knows to not draw placeholder if you're using the attributed placeholder.
Overriding drawPlaceholderInRect: would be the correct way, but it does not work due to a bug in the API (or the documentation).
The method never gets called on an UITextField.
See also drawTextInRect on UITextField not called
You might use digdog's solution. As I am not sure if that gets past Apples review, I chose a different solution: Overlay the text field with my own label which imitates the placeholder behaviour.
This is a bit messy though.
The code looks like this (Note I am doing this inside a subclass of TextField):
#implementation PlaceholderChangingTextField
- (void) changePlaceholderColor:(UIColor*)color
{
// Need to place the overlay placeholder exactly above the original placeholder
UILabel *overlayPlaceholderLabel = [[[UILabel alloc] initWithFrame:CGRectMake(self.frame.origin.x + 8, self.frame.origin.y + 4, self.frame.size.width - 16, self.frame.size.height - 8)] autorelease];
overlayPlaceholderLabel.backgroundColor = [UIColor whiteColor];
overlayPlaceholderLabel.opaque = YES;
overlayPlaceholderLabel.text = self.placeholder;
overlayPlaceholderLabel.textColor = color;
overlayPlaceholderLabel.font = self.font;
// Need to add it to the superview, as otherwise we cannot overlay the buildin text label.
[self.superview addSubview:overlayPlaceholderLabel];
self.placeholder = nil;
}
Iam new to xcode and i found a way around to the same effect.
I placed a uilabel in place of place holder with the desired format and hide it in
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
switch (textField.tag)
{
case 0:
lblUserName.hidden=YES;
break;
case 1:
lblPassword.hidden=YES;
break;
default:
break;
}
}
I agree its a work around and not a real solution but the effect was same got it from this link
NOTE: Still works on iOS 7 :|
The best i can do for both iOS7 and less is:
- (CGRect)placeholderRectForBounds:(CGRect)bounds {
return [self textRectForBounds:bounds];
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
return [self textRectForBounds:bounds];
}
- (CGRect)textRectForBounds:(CGRect)bounds {
CGRect rect = CGRectInset(bounds, 0, 6); //TODO: can be improved by comparing font size versus bounds.size.height
return rect;
}
- (void)drawPlaceholderInRect:(CGRect)rect {
UIColor *color =RGBColor(65, 65, 65);
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
[self.placeholder drawInRect:rect withAttributes:#{NSFontAttributeName:self.font, UITextAttributeTextColor:color}];
} else {
[color setFill];
[self.placeholder drawInRect:rect withFont:self.font];
}
}
For those using Monotouch (Xamarin.iOS), here's Adam's answer, translated to C#:
public class MyTextBox : UITextField
{
public override void DrawPlaceholder(RectangleF rect)
{
UIColor.FromWhiteAlpha(0.5f, 1f).SetFill();
new NSString(this.Placeholder).DrawString(rect, Font);
}
}
For set Attributed Textfield Placeholder with Multiple color ,
Just specify the Text ,
//txtServiceText is your Textfield
_txtServiceText.placeholder=#"Badal/ Shah";
NSMutableAttributedString *mutable = [[NSMutableAttributedString alloc] initWithString:_txtServiceText.placeholder];
[mutable addAttribute: NSForegroundColorAttributeName value:[UIColor whiteColor] range:[_txtServiceText.placeholder rangeOfString:#"Badal/"]]; //Replace it with your first color Text
[mutable addAttribute: NSForegroundColorAttributeName value:[UIColor orangeColor] range:[_txtServiceText.placeholder rangeOfString:#"Shah"]]; // Replace it with your secondcolor string.
_txtServiceText.attributedPlaceholder=mutable;
Output :-
I needed to keep the placeholder alignment so adam's answer was not enough for me.
To solve this I used a small variation that I hope will help some of you too:
- (void) drawPlaceholderInRect:(CGRect)rect {
//search field placeholder color
UIColor* color = [UIColor whiteColor];
[color setFill];
[self.placeholder drawInRect:rect withFont:self.font lineBreakMode:UILineBreakModeTailTruncation alignment:self.textAlignment];
}
[txt_field setValue:ColorFromHEX(#"#525252") forKeyPath:#"_placeholderLabel.textColor"];
Another option that doesn't require subclassing - leave placeholder blank, and put a label on top of edit button. Manage the label just like you would manage the placeholder (clearing once user inputs anything..)

Resources