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..)
Related
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];
}
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
I want some words within my OHAttributedLabel to be links, but I want them to be colors other than blue and I don't want the underline.
This is giving me a blue link with underlined text:
-(void)createLinkFromWord:(NSString*)word withColor:(UIColor*)color atRange:(NSRange)range{
NSMutableAttributedString* mutableAttributedText = [self.label.attributedText mutableCopy];
[mutableAttributedText beginEditing];
[mutableAttributedText addAttribute:kOHLinkAttributeName
value:[NSURL URLWithString:#"http://www.somewhere.net"]
range:range];
[mutableAttributedText addAttribute:(id)kCTForegroundColorAttributeName
value:color
range:range];
[mutableAttributedText addAttribute:(id)kCTUnderlineStyleAttributeName
value:[NSNumber numberWithInt:kCTUnderlineStyleNone]
range:range];
[mutableAttributedText endEditing];
self.label.attributedText = mutableAttributedText;
}
Since I'm using OHAttributedLabel, I also tried using the methods in it's NSAttributedString+Attributes.h category, but those return blue underlined links as well:
-(void)createLinkFromWord:(NSString*)word withColor:(UIColor*)color atRange:(NSRange)range{
NSMutableAttributedString* mutableAttributedText = [self.label.attributedText mutableCopy];
[mutableAttributedText setLink:[NSURL URLWithString:#"http://www.somewhere.net"] range:range];
[mutableAttributedText setTextColor:color range:range];
[mutableAttributedText setTextUnderlineStyle:kCTUnderlineStyleNone range:range];
self.label.attributedText = mutableAttributedText;
}
If I comment out the line setting the links in each version, the text gets colored to what I pass in - that works. It just seems like setting the link is overriding this and turning it back to blue.
Unfortunately the apple docs page I found shows how to set the link text to blue and underline it, exactly what I don't need:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/AttributedStrings/Tasks/ChangingAttrStrings.html
So I ended up using TTTAttributedLabel:
-(void)createLinkFromWord:(NSString*)word withColor:(UIColor*)color atRange:(NSRange)range{
NSMutableAttributedString* newTextWithLinks = [self.label.attributedText mutableCopy];
NSURL *url = [NSURL URLWithString:#"http://www.reddit.com"];
self.label.linkAttributes = #{NSForegroundColorAttributeName: color,
NSUnderlineStyleAttributeName: #(NSUnderlineStyleNone)};
[self.label addLinkToURL:url withRange:range];
}
I found that OHAttributedLabel actually does have methods to set links and declare colors and underline styles for those links. However, I wanted the links to be different colors based on a parameter. TTTAttributedLabel allows this by letting you set it's linkAttributes property for each link you create.
I am using TTTAttributedLabel. I wanted to change the color of the linked text, and keep it underlined. Pim's answer looked great, but didn't work for me. Here's what did work:
label.linkAttributes = #{ (id)kCTForegroundColorAttributeName: [UIColor magentaColor],
(id)kCTUnderlineStyleAttributeName : [NSNumber numberWithInt:NSUnderlineStyleSingle] };
Note: if you don't want the text underlined, then remove the kCTUnderlineStyleAttributeName key from the dictionary.
Here's is my improved version of Ramsel's already great answer.
I believe it's much more readable, and I hope it will come to good use.
label.linkAttributes = #{ NSForegroundColorAttributeName: [UIColor whiteColor],
NSUnderlineStyleAttributeName: [NSNumber numberWithInt:NSUnderlineStyleSingle] };
Here's a list of other attibute names.
If you're using a UITextView, you might have to change the tintColor property to change the link color.
If you're like me and really don't want to use TTT (or need it in your own custom implementation where you're drawing in other weird ways):
First, subclass NSLayoutManager and then override as follows:
- (void)showCGGlyphs:(const CGGlyph *)glyphs
positions:(const CGPoint *)positions
count:(NSUInteger)glyphCount
font:(UIFont *)font
matrix:(CGAffineTransform)textMatrix
attributes:(NSDictionary *)attributes
inContext:(CGContextRef)graphicsContext
{
UIColor *foregroundColor = attributes[NSForegroundColorAttributeName];
if (foregroundColor)
{
CGContextSetFillColorWithColor(graphicsContext, foregroundColor.CGColor);
}
[super showCGGlyphs:glyphs
positions:positions
count:glyphCount
font:font
matrix:textMatrix
attributes:attributes
inContext:graphicsContext];
}
This is more or less telling the layout manager to actually respect NSForegroundColorAttributeName from your attributed string always instead of the weirdness Apple has internally for links.
If all you need to do is get a layout manager which draws correctly (as I needed), you can stop here. If you need an actually UILabel, it's painful but possible.
First, again, subclass UILabel and slap in all of these methods.
- (NSTextStorage *)textStorage
{
if (!_textStorage)
{
_textStorage = [[NSTextStorage alloc] init];
[_textStorage addLayoutManager:self.layoutManager];
[self.layoutManager setTextStorage:_textStorage];
}
return _textStorage;
}
- (NSTextContainer *)textContainer
{
if (!_textContainer)
{
_textContainer = [[NSTextContainer alloc] init];
_textContainer.lineFragmentPadding = 0;
_textContainer.maximumNumberOfLines = self.numberOfLines;
_textContainer.lineBreakMode = self.lineBreakMode;
_textContainer.widthTracksTextView = YES;
_textContainer.size = self.frame.size;
[_textContainer setLayoutManager:self.layoutManager];
}
return _textContainer;
}
- (NSLayoutManager *)layoutManager
{
if (!_layoutManager)
{
// Create a layout manager for rendering
_layoutManager = [[PRYLayoutManager alloc] init];
_layoutManager.delegate = self;
[_layoutManager addTextContainer:self.textContainer];
}
return _layoutManager;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Update our container size when the view frame changes
self.textContainer.size = self.bounds.size;
}
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
CGSize size = frame.size;
size.width = MIN(size.width, self.preferredMaxLayoutWidth);
size.height = 0;
self.textContainer.size = size;
}
- (void)setBounds:(CGRect)bounds
{
[super setBounds:bounds];
CGSize size = bounds.size;
size.width = MIN(size.width, self.preferredMaxLayoutWidth);
size.height = 0;
self.textContainer.size = size;
}
- (void)setPreferredMaxLayoutWidth:(CGFloat)preferredMaxLayoutWidth
{
[super setPreferredMaxLayoutWidth:preferredMaxLayoutWidth];
CGSize size = self.bounds.size;
size.width = MIN(size.width, self.preferredMaxLayoutWidth);
self.textContainer.size = size;
}
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines
{
// Use our text container to calculate the bounds required. First save our
// current text container setup
CGSize savedTextContainerSize = self.textContainer.size;
NSInteger savedTextContainerNumberOfLines = self.textContainer.maximumNumberOfLines;
// Apply the new potential bounds and number of lines
self.textContainer.size = bounds.size;
self.textContainer.maximumNumberOfLines = numberOfLines;
// Measure the text with the new state
CGRect textBounds;
#try
{
NSRange glyphRange = [self.layoutManager
glyphRangeForTextContainer:self.textContainer];
textBounds = [self.layoutManager boundingRectForGlyphRange:glyphRange
inTextContainer:self.textContainer];
// Position the bounds and round up the size for good measure
textBounds.origin = bounds.origin;
textBounds.size.width = ceilf(textBounds.size.width);
textBounds.size.height = ceilf(textBounds.size.height);
}
#finally
{
// Restore the old container state before we exit under any circumstances
self.textContainer.size = savedTextContainerSize;
self.textContainer.maximumNumberOfLines = savedTextContainerNumberOfLines;
}
return textBounds;
}
- (void)setAttributedText:(NSAttributedString *)attributedText
{
// Pass the text to the super class first
[super setAttributedText:attributedText];
[self.textStorage setAttributedString:attributedText];
}
- (CGPoint)_textOffsetForGlyphRange:(NSRange)glyphRange
{
CGPoint textOffset = CGPointZero;
CGRect textBounds = [self.layoutManager boundingRectForGlyphRange:glyphRange
inTextContainer:self.textContainer];
CGFloat paddingHeight = (self.bounds.size.height - textBounds.size.height) / 2.0f;
if (paddingHeight > 0)
{
textOffset.y = paddingHeight;
}
return textOffset;
}
- (void)drawTextInRect:(CGRect)rect
{
// Calculate the offset of the text in the view
CGPoint textOffset;
NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
textOffset = [self _textOffsetForGlyphRange:glyphRange];
// Drawing code
[self.layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:textOffset];
// for debugging the following 2 line should produce the same results
[self.layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:textOffset];
//[super drawTextInRect:rect];
}
Shamelessly taken from here. Incredibly work on the original author's part for working this all out.
Swift 2.3 example for TTTAttributedLabel:
yourLabel.linkAttributes = [
NSForegroundColorAttributeName: UIColor.grayColor(),
NSUnderlineStyleAttributeName: NSNumber(bool: true)
]
yourLabel.activeLinkAttributes = [
NSForegroundColorAttributeName: UIColor.grayColor().colorWithAlphaComponent(0.8),
NSUnderlineStyleAttributeName: NSNumber(bool: false)
]
Swift 4
yourLabel.linkAttributes = [
.foregroundColor: UIColor.grayColor(),
.underlineStyle: NSNumber(value: true)
]
yourLabel.activeLinkAttributes = [
.foregroundColor: UIColor.grayColor().withAlphaComponent(0.7),
.underlineStyle: NSNumber(value: false)
]
For Swift 3 following way worked out for me using TTTAttributedLabel:
1) Add a label on the storyboard and define its class to be TTTAttributedLabel
2) In code define
#IBOutlet var termsLabel: TTTAttributedLabel!
3) Then in ViewDidLoad write these lines
termsLabel.attributedText = NSAttributedString(string: "By using this app you agree to the Privacy Policy & Terms & Conditions.")
guard let labelString = termsLabel.attributedText else {
return
}
guard let privacyRange = labelString.string.range(of: "Privacy Policy") else {
return
}
guard let termsConditionRange = labelString.string.range(of: "Terms & Conditions") else {
return
}
let privacyNSRange: NSRange = labelString.string.nsRange(from: privacyRange)
let termsNSRange: NSRange = labelString.string.nsRange(from: termsConditionRange)
termsLabel.addLink(to: URL(string: "privacy"), with: privacyNSRange)
termsLabel.addLink(to: URL(string: "terms"), with: termsNSRange)
termsLabel.delegate = self
let attributedText = NSMutableAttributedString(attributedString: termsLabel.attributedText!)
attributedText.addAttributes([NSFontAttributeName : UIFont(name: "Roboto-Medium", size: 12)!], range: termsNSRange)
attributedText.addAttributes([NSFontAttributeName : UIFont(name: "Roboto-Medium", size: 12)!], range: privacyNSRange)
attributedText.addAttributes([kCTForegroundColorAttributeName as String: UIColor.orange], range: termsNSRange)
attributedText.addAttributes([kCTForegroundColorAttributeName as String: UIColor.green], range: privacyNSRange)
attributedText.addAttributes([NSUnderlineStyleAttributeName: NSUnderlineStyle.styleNone.rawValue], range: termsNSRange)
attributedText.addAttributes([NSUnderlineStyleAttributeName: NSUnderlineStyle.styleNone.rawValue], range: privacyNSRange)
termsLabel.attributedText = attributedText
It would look like this
4) Finally write the delegate function of TTTAttributedLabel so that you can open links on tap
public func attributedLabel(_ label: TTTAttributedLabel!, didSelectLinkWith url: URL!) {
switch url.absoluteString {
case "privacy":
SafariBrowser.open("http://google.com", presentingViewController: self)
case "terms":
SafariBrowser.open("http://google.com", presentingViewController: self)
default:
break
}
}
Update for Swift 4.2
For Swift 4.2, there are some changes in step 3, all other steps would remain same as above:
3) In ViewDidLoad write these lines
termsLabel.attributedText = NSAttributedString(string: "By using this app you agree to the Privacy Policy & Terms & Conditions.")
guard let labelString = termsLabel.attributedText else {
return
}
guard let privacyRange = labelString.string.range(of: "Privacy Policy") else {
return
}
guard let termsConditionRange = labelString.string.range(of: "Terms & Conditions") else {
return
}
let privacyNSRange: NSRange = labelString.string.nsRange(from: privacyRange)
let termsNSRange: NSRange = labelString.string.nsRange(from: termsConditionRange)
termsLabel.addLink(to: URL(string: "privacy"), with: privacyNSRange)
termsLabel.addLink(to: URL(string: "terms"), with: termsNSRange)
termsLabel.delegate = self
let attributedText = NSMutableAttributedString(attributedString: termsLabel.attributedText!)
attributedText.addAttributes([NSAttributedString.Key.font : UIFont(name: "Roboto-Regular", size: 12)!], range: termsNSRange)
attributedText.addAttributes([NSAttributedString.Key.font : UIFont(name: "Roboto-Regular", size: 12)!], range: privacyNSRange)
attributedText.addAttributes([kCTForegroundColorAttributeName as NSAttributedString.Key : UIColor.orange], range: termsNSRange)
attributedText.addAttributes([kCTForegroundColorAttributeName as NSAttributedString.Key : UIColor.green], range: privacyNSRange)
attributedText.addAttributes([NSAttributedString.Key.underlineStyle: 0], range: termsNSRange)
attributedText.addAttributes([NSAttributedString.Key.underlineStyle: 0], range: privacyNSRange)
Swift 3 example for TTTAttributedLabel:
yourLabel.linkAttributes = [
NSForegroundColorAttributeName: UIColor.green,
NSUnderlineStyleAttributeName: NSNumber(value: NSUnderlineStyle.styleNone.rawValue)
]
yourLabel.activeLinkAttributes = [
NSForegroundColorAttributeName: UIColor.green,
NSUnderlineStyleAttributeName: NSNumber(value: NSUnderlineStyle.styleDouble.rawValue)
]
For Swift 3 using TTTAttributedLabel
let title: NSString = "Fork me on GitHub!"
var attirutedDictionary = NSMutableDictionary(dictionary:attributedLabel.linkAttributes)
attirutedDictionary[NSForegroundColorAttributeName] = UIColor.red
attirutedDictionary[NSUnderlineStyleAttributeName] = NSNumber(value: NSUnderlineStyle.styleNone.rawValue)
attributedLabel.attributedText = NSAttributedString(string: title as String)
attributedLabel.linkAttributes = attirutedDictionary as! [AnyHashable: Any]
let range = subtitleTitle.range(of: "me")
let url = URL(string: "http://github.com/mattt/")
attributedLabel.addLink(to: url, with: range)
Swift 4.0 :
Short and simple
let LinkAttributes = NSMutableDictionary(dictionary: testLink.linkAttributes)
LinkAttributes[NSAttributedStringKey.underlineStyle] = NSNumber(value: false)
LinkAttributes[NSAttributedStringKey.foregroundColor] = UIColor.black // Whatever your label color
testLink.linkAttributes = LinkAttributes as NSDictionary as! [AnyHashable: Any]
It's better to use UITextView with "Link" feature enabled. In this case you can do it with one line:
Swift 4:
// apply link attributes to label.attributedString, then
textView.tintColor = UIColor.red // any color you want
Full example:
let attributedString = NSMutableAttributedString(string: "Here is my link")
let range = NSRange(location: 7, length:4)
attributedString.addAttribute(.link, value: "http://google.com", range: range)
attributedString.addAttribute(.underlineStyle, value: 1, range: range)
attributedString.addAttribute(.underlineColor, value: UIColor.red, range: range)
textView.tintColor = UIColor.red // any color you want
Or you can apply attributes to links only:
textView.linkTextAttributes = [
.foregroundColor: UIColor.red
.underlineStyle: 1,
.underlineColor: UIColor.red
]
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:
What is the easiest way to have a label with different colors?
For example I want to present the message:
"John Johnson sent you a message"
But I want that John Johnson will be in blue color
and the rest of the message in black color.
You need the NSAttributedString class (or the mutable one - NSMutableAttributedString) in order to set attributes (for example, font and kerning) that apply to individual characters or ranges of characters in the string and a custom label control that can visualize NSAttributedString like TTTAttributedLabel.
In UILabel basically impossible. If you want to this you must override drawTextInRect should be executed. But I will recommend OHAttributedLabel. this is have a attributedString is a textcolor can be set to specify a range.
Use a UIWebView.
webView.text =
#"<span style:\"color:blue;\">John Johnson</span> sent you a message.";
Use CoreText. Hope this helps.
I created an UILabel extension to do this. Basically what it does is use NSAttributedString to define the color for some particular range: https://github.com/joaoffcosta/UILabel-FormattedText
If you wish to implement this behavior yourself, just do the following:
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithAttributedString: #"John Johnson sent you a message"];
[text addAttribute: NSFontAttributeName
value: font
range: range];
[self setAttributedText: text];
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:
let label = UILabel()
label.frame = CGRect(x: 40, y: 100, width: 280, height: 200)
let stringValue = "John Johnson sent you a message" // or direct assign single string value like "firstsecondthird"
label.textColor = UIColor.lightGray
label.numberOfLines = 0
let attributedString: NSMutableAttributedString = NSMutableAttributedString(string: stringValue)
attributedString.setColorForText(textToFind: "John Johnson", withColor: UIColor.blue)
label.font = UIFont.systemFont(ofSize: 26)
label.attributedText = attributedString
self.view.addSubview(label)
Here is result: