Subclassing UIViewController With NavigationBar Title - ios

I'm trying to subclass a UIViewController with a label (UILabel) set to the title of the navigation bar. Instead of setting a name to self.title, I want to use an attributed string to set the title.
class BasicViewController: UIViewController {
var titleString = ""
func setup() {
//self.title = titleString
let navBar = navigationController!.navigationBar
navBar.barTintColor = UIColor.redColor()
let atext = NSMutableAttributedString(string: titleString)
atext.addAttribute(NSForegroundColorAttributeName, value: UIColor.whiteColor(), range: NSMakeRange(0, atext.length))
atext.addAttribute(NSStrokeColorAttributeName, value: UIColor.yellowColor(), range: NSMakeRange(0, atext.length))
atext.addAttribute(NSStrokeWidthAttributeName, value: NSNumber.init(float: -1.0), range: NSMakeRange(0, atext.length))
let titleLabel:UILabel = UILabel.init(frame: CGRectMake(50, 3, 220, 44))
titleLabel.attributedText = atext
titleLabel.textAlignment = NSTextAlignment.Center
titleLabel.font = UIFont(name: "Helvetica", size: 24.0)
}
}
class HomeViewController: BasicViewController {
override func viewDidLoad() {
super.viewDidLoad()
titleString = "My App"
setup()
}
}
If I run this code, I get an empty title. What am I doing wrong? Thanks.

I don't see where you're setting self.navigationItem.titleView = titleLabel

Related

Swift - UITextView text is getting cut when applying custom font

I am using UITextView inside super view UIView to display text with many different types of fonts.
But UITextView text is getting cut when applying specific font Smoothie_Life_Swirls_2.0
I am creating textView programmatically as below,
textView = ResizableTextView(frame: CGRect(x: 0, y: 0, width: contentView.frame.size.width, height: contentView.frame.size.height))
textView.isScrollEnabled = false
textView.alignment = .center
textView.backgroundColor = UIColor.clear
textView.fontName = "Helveticas"
textView.fontSize = contentView.frame.size.height
textView.textColor = textColor
textView.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin, .flexibleBottomMargin, .flexibleLeftMargin, .flexibleWidth, .flexibleHeight]
textView.delegate = self
contentView.addSubview(textView)
textView.becomeFirstResponder()
Here ResizableTextView is my UITextView class, in which fontName and fontSize will be set
public class ResizableTextView: UITextView {
public private(set) var textAttributes: [String: AnyObject] = [:]
public var fontName: String = "Helvetica" {
didSet {
let font = UIFont(name: fontName, size: fontSize)
textAttributes[NSFontAttributeName] = font
self.attributedText = NSAttributedString(string: self.text, attributes: textAttributes)
self.font = font
}
}
public var fontSize: CGFloat = 20 {
didSet {
let font = UIFont(name: fontName, size: fontSize)
textAttributes[NSFontAttributeName] = font
self.attributedText = NSAttributedString(string: self.text, attributes: textAttributes)
self.font = font
}
}
}
When I set Smoothie_Life_Swirls_2.0 font to textView using ResizableTextView's fontName property, at that time text is getting cut.
Text1 - Getting Output
Text2 - Required Output
I want to fit the text in UITextView same as Text2, but I am getting the result as displayed in Text1.

Adjust font size of NSMutableAttributedString proportional to UILabel's frame height

In my project, I am using swift 3.0. Right now I am using following class (UILabel subclass) to adjust font size based on UILabel frame height. When UILabel frame change occurs, layoutSubviews recalculates proportional font size.
class Label: UILabel {
// FIXME: - properties
var fontSize: CGFloat = 0
var frameHeight: CGFloat = 0
// FIXME: - proportional font size adjustment
override func layoutSubviews() {
super.layoutSubviews()
font = font.withSize(frame.size.height * (fontSize / frameHeight))
}
}
HOW TO USE:
private let id: Label = {
let label = Label()
label.textAlignment = .left
label.numberOfLines = 1
label.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
label.textColor = UIColor(hex: 0x212121, alpha: 1)
label.fontSize = 17
label.frameHeight = 20
label.clipsToBounds = true
return label
}()
Now I want to show some part of String in UILabel as BOLD TEXT and remaining in REGULAR TEXT. So I have found some help on this thread: Making text bold using attributed string in swift
I am using "Prajeet Shrestha's" extension for NSMutableAttributedString.
// "Prajeet Shrestha's" extension
extension NSMutableAttributedString {
func bold(_ text:String) -> NSMutableAttributedString {
let attrs:[String:AnyObject] = [NSFontAttributeName : UIFont(name: "AvenirNext-Medium", size: 12)!]
let boldString = NSMutableAttributedString(string:"\(text)", attributes:attrs)
self.append(boldString)
return self
}
func normal(_ text:String)->NSMutableAttributedString {
let normal = NSAttributedString(string: text)
self.append(normal)
return self
}
}
But I am not getting how I can change font size of this NSMutableAttributedString, when UILabel frame change occurs?
Any help appeciated.
Try this
Source Looping Through NSAttributedString Attributes to Increase Font SIze
mutableStringObj?.enumerateAttribute(NSFontAttributeName, in: NSRange(location: 0, length: mutableStringObj?.length), options: [], usingBlock: {(_ value: Any, _ range: NSRange, _ stop: Bool) -> Void in
if value {
var oldFont: UIFont? = (value as? UIFont)
var newFont: UIFont? = oldFont?.withSize(CGFloat(oldFont?.pointSize * 2))
res?.removeAttribute(NSFontAttributeName, range: range)
res?.addAttribute(NSFontAttributeName, value: newFont, range: range)
}
})
Finally come up with an answer.
I created seperate custom UILabel subclass as follows:
class AttrLabel: UILabel {
// FIXME: - properties
var fontSize: CGFloat = 0
var frameHeight: CGFloat = 0
// FIXME: - proportional font size adjustment
override func layoutSubviews() {
super.layoutSubviews()
guard let oldAttrText = attributedText else {
return
}
let mutableAttributedText = NSMutableAttributedString(attributedString: oldAttrText)
mutableAttributedText.beginEditing()
mutableAttributedText.enumerateAttribute(NSFontAttributeName, in: NSRange(location: 0, length: mutableAttributedText.length), options: []) { (_ value: Any?, _ range: NSRange, _ stop: UnsafeMutablePointer<ObjCBool>) in
if let attributeFont = value as? UIFont {
let newFont = attributeFont.withSize(self.frame.size.height * (self.fontSize / self.frameHeight))
mutableAttributedText.removeAttribute(NSFontAttributeName, range: range)
mutableAttributedText.addAttribute(NSFontAttributeName, value: newFont, range: range)
}
}
mutableAttributedText.endEditing()
attributedText = mutableAttributedText
}
}
HOW TO USE:
private let id: AttrLabel = {
let label = AttrLabel()
label.textAlignment = .left
label.numberOfLines = 1
label.fontSize = 17
label.frameHeight = 20
label.clipsToBounds = true
return label
}()
SETTING ATTRIBUTED TEXT
let idStr = NSMutableAttributedString()
id.attributedText = idStr.attrStr(text: "BOLD TEXT: ", font: UIFont.systemFont(ofSize: 17, weight: .semibold), textColor: UIColor(hex: 0x212121, alpha: 1)).attrStr(text: "REGULAR WEIGHT TEXT.", font: UIFont.systemFont(ofSize: 17, weight: .regular), textColor: UIColor(hex: 0x212121, alpha: 1))
"Prajeet Shrestha's" extension for NSMutableAttributedString modified by me
extension NSMutableAttributedString {
func attrStr(text: String, font: UIFont, textColor: UIColor) -> NSMutableAttributedString {
let attributes: [String: Any] = [
NSFontAttributeName: font,
NSForegroundColorAttributeName: textColor
]
let string = NSMutableAttributedString(string: text, attributes: attributes)
self.append(string)
return self
}
}
Try Using label property adjustsFontSizeToFitWidth AND minimumScaleFactor like this:
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.2
then you also need to increase number of lines like this any number instead of 10
label.numberOfLines = 10

Swift - UIButton with two lines of text

I was wondering if it is possible to create a UIButton with two lines of text. I need each line to have a different font size. The first line will be 17 point and the second will be 11 point. I've tried messing with putting two labels inside of a UIButton, but I can't get them to stay inside the bounds of the button.
I'm attempting to do all of this in the ui builder, and not programmatically.
Thanks
There are two questions.
I was wondering if it is possible to create a UIButton with two lines
of text
This is possible through using the storyboard or programmatically.
Storyboard:
Change the 'Line Break Mode' to Character Wrap or Word Wrap and use Alt/Option + Enter key to enter a new line in the UIButton's Title field.
Programmatically:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
btnTwoLine?.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping;
}
I need each line to have a different font size
1
The worst case is, you can use a custom UIButton class and add two labels within it.
The better way is, make use of NSMutableAttributedString. Note that,this can be achieved through only programmatically.
Swift 5:
#IBOutlet weak var btnTwoLine: UIButton?
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
//applying the line break mode
textResponseButton?.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping;
let buttonText: NSString = "hello\nthere"
//getting the range to separate the button title strings
let newlineRange: NSRange = buttonText.range(of: "\n")
//getting both substrings
var substring1 = ""
var substring2 = ""
if(newlineRange.location != NSNotFound) {
substring1 = buttonText.substring(to: newlineRange.location)
substring2 = buttonText.substring(from: newlineRange.location)
}
//assigning diffrent fonts to both substrings
let font1: UIFont = UIFont(name: "Arial", size: 17.0)!
let attributes1 = [NSMutableAttributedString.Key.font: font1]
let attrString1 = NSMutableAttributedString(string: substring1, attributes: attributes1)
let font2: UIFont = UIFont(name: "Arial", size: 11.0)!
let attributes2 = [NSMutableAttributedString.Key.font: font2]
let attrString2 = NSMutableAttributedString(string: substring2, attributes: attributes2)
//appending both attributed strings
attrString1.append(attrString2)
//assigning the resultant attributed strings to the button
textResponseButton?.setAttributedTitle(attrString1, for: [])
}
Older Swift
#IBOutlet weak var btnTwoLine: UIButton?
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
//applying the line break mode
btnTwoLine?.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping;
var buttonText: NSString = "hello\nthere"
//getting the range to separate the button title strings
var newlineRange: NSRange = buttonText.rangeOfString("\n")
//getting both substrings
var substring1: NSString = ""
var substring2: NSString = ""
if(newlineRange.location != NSNotFound) {
substring1 = buttonText.substringToIndex(newlineRange.location)
substring2 = buttonText.substringFromIndex(newlineRange.location)
}
//assigning diffrent fonts to both substrings
let font:UIFont? = UIFont(name: "Arial", size: 17.0)
let attrString = NSMutableAttributedString(
string: substring1 as String,
attributes: NSDictionary(
object: font!,
forKey: NSFontAttributeName) as [NSObject : AnyObject])
let font1:UIFont? = UIFont(name: "Arial", size: 11.0)
let attrString1 = NSMutableAttributedString(
string: substring2 as String,
attributes: NSDictionary(
object: font1!,
forKey: NSFontAttributeName) as [NSObject : AnyObject])
//appending both attributed strings
attrString.appendAttributedString(attrString1)
//assigning the resultant attributed strings to the button
btnTwoLine?.setAttributedTitle(attrString, forState: UIControlState.Normal)
}
Output
I was looking for nearly the same topic, except that I don't need two different font sizes. In case someone is looking for a simple solution:
let button = UIButton()
button.titleLabel?.numberOfLines = 0
button.titleLabel?.lineBreakMode = .byWordWrapping
button.setTitle("Foo\nBar", for: .normal)
button.titleLabel?.textAlignment = .center
button.sizeToFit()
button.addTarget(self, action: #selector(rightBarButtonTapped), for: .allEvents)
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
I have notice an issue in most of the solutions which is while making line break mode to "Character Wrap" the second line will be left aligned to the first line
To make all the lines centered.
just change the title From Plain to Attributed and then you can make each line centered
change line break to character wrap , select your button and in attribute inspector go to line break and change it to character wrap
SWIFT 3 Syntax
let str = NSMutableAttributedString(string: "First line\nSecond Line")
str.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 17), range: NSMakeRange(0, 10))
str.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 12), range: NSMakeRange(11, 11))
button.setAttributedTitle(str, for: .normal)
I have fixed this and my solution it was only in the Storyboard.
Changes:
It added in Identity Inspector -> User Defined Runtime Attributes (these KeyPaths):
numberOfLines = 2
titleLabel.textAlignment = 1
User Defined Runtime Attributes
I added this in attributes inspector:
line break = word wrap
Word wrap
You need to do some of this in code. you can't set 2 different fonts in IB. In addition to changing the line break mode to character wrap, you need something like this to set the title,
override func viewDidLoad() {
super.viewDidLoad()
var str = NSMutableAttributedString(string: "First line\nSecond Line")
str.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(17), range: NSMakeRange(0, 10))
str.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(12), range: NSMakeRange(11, 11))
button.setAttributedTitle(str, forState: .Normal)
}
New with Xcode 13 (iOS 15)
Starting with Xcode 13, the button's title and subtitle may have their attributes set separately.
Using Storyboard:
In the Attribute Inspector for the button, select "Attributed" by Title. Then change font size of the title and the subtitle.
Or Programmatically:
// Create Title
let titleSettings = AttributeContainer.font( UIFont(name: "HelveticaNeue-Italic", size: 17)! )
yourButton.configuration?.attributedTitle = AttributedString("Button's Title", attributes: titleSettings)
// Create Subtitle
let subtitleSettings = AttributeContainer.font( UIFont(name: "HelveticaNeue-Italic", size: 11)! )
yourButton.configuration?.attributedSubtitle = AttributedString("Button's Subtitle", attributes: subtitleSettings)
One way to do it is with labels, I guess. I did this, and it seems to work ok. I could create this as a UIButton and then expose the labels, I guess. I don't know if this makes any sense.
let firstLabel = UILabel()
firstLabel.backgroundColor = UIColor.lightGrayColor()
firstLabel.text = "Hi"
firstLabel.textColor = UIColor.blueColor()
firstLabel.textAlignment = NSTextAlignment.Center
firstLabel.frame = CGRectMake(0, testButton.frame.height * 0.25, testButton.frame.width, testButton.frame.height * 0.2)
testButton.addSubview(firstLabel)
let secondLabel = UILabel()
secondLabel.backgroundColor = UIColor.lightGrayColor()
secondLabel.textColor = UIColor.blueColor()
secondLabel.font = UIFont(name: "Arial", size: 12)
secondLabel.text = "There"
secondLabel.textAlignment = NSTextAlignment.Center
secondLabel.frame = CGRectMake(0, testButton.frame.height * 0.5, testButton.frame.width, testButton.frame.height * 0.2)
testButton.addSubview(secondLabel)
The suggested solutions unfortunately did not work out for me when I wanted to have a mutliline button inside a CollectionView. Then a colleague showed me a workaround which I wanted to share in case someone has the same problem - hope this helps! Create a class which inherits from UIControl and extend it with a label, which will then behave similar like a button.
class MultilineButton: UIControl {
let label: UILabel = {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.numberOfLines = 0
$0.textAlignment = .center
return $0
}(UILabel())
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(label)
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
label.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
label.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor)
])
}
override var isHighlighted: Bool {
didSet {
backgroundColor = backgroundColor?.withAlphaComponent(isHighlighted ? 0.7 : 1.0)
label.textColor = label.textColor.withAlphaComponent(isHighlighted ? 0.7 : 1.0)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
my way:
func setButtonTitle(title: String, subtitle: String, button: UIButton){
//applying the line break mode
button.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping;
let title = NSMutableAttributedString(string: title, attributes: Attributes.biggestLabel)
let subtitle = NSMutableAttributedString(string: subtitle, attributes: Attributes.label)
let char = NSMutableAttributedString(string: "\n", attributes: Attributes.biggestLabel)
title.append(char)
title.append(subtitle)
button.setAttributedTitle(title, for: .normal)
}

Center align placeholder in textfield

I know this question been asked many times but as drawinrect deprecated and I need this in ios 8.As I have a textfield and I need the placeholder in center align and rest of the test left align.Please help me out.
You can center the placeholder by using an attributedPlaceholder with a paragraph style whose alignment is set to .center:
let centeredParagraphStyle = NSMutableParagraphStyle()
centeredParagraphStyle.alignment = .center
textField.attributedPlaceholder = NSAttributedString(
string: "Placeholder",
attributes: [.paragraphStyle: centeredParagraphStyle]
)
Create and connect IBOutlet to your textField. In YourViewController.m
#interface YourViewController () <UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITextField *txt;
In your viewDidLoad
self.txt.delegate=self;
self.txt.textAlignment=NSTextAlignmentCenter;
Write this delegate method..this method calls everytime when text in text field changes.
- (BOOL) textField: (UITextField *)theTextField shouldChangeCharactersInRange: (NSRange)range replacementString: (NSString *)string {
NSRange textFieldRange = NSMakeRange(0, [self.txt.text length]);
// Check If textField is empty. If empty align your text field to center, so that placeholder text will show center aligned
if (NSEqualRanges(range, textFieldRange) && [string length] == 0) {
self.txt.textAlignment=NSTextAlignmentCenter;
}
else //else align textfield to left.
{
self.txt.textAlignment=NSTextAlignmentLeft;
}
return YES;
}
The answer by #Clay Ellis is correct, here it is for Objective-C:
UITextField* field = [[UITextField alloc] initWithFrame: fieldRect];
NSTextAlignment alignment = NSTextAlignmentCenter;
NSMutableParagraphStyle* alignmentSetting = [[NSMutableParagraphStyle alloc] init];
alignmentSetting.alignment = alignment;
NSDictionary *attributes = #{NSParagraphStyleAttributeName : alignmentSetting};
NSAttributedString *str = [[NSAttributedString alloc] initWithString:placeholder attributes: attributes];
field.attributedPlaceholder = str;
The answer by #Clay Ellis in Swift 5
let centeredParagraphStyle = NSMutableParagraphStyle()
centeredParagraphStyle.alignment = .center
let attributedPlaceholder = NSAttributedString(string: "Placeholder", attributes: [NSAttributedString.Key.paragraphStyle: centeredParagraphStyle])
textField.attributedPlaceholder = attributedPlaceholder
based on Clay Ellis answer
Details
Xcode Version 10.2.1 (10E1001), Swift 5
Solution 1
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
textField.attributedText = NSAttributedString(string: placeholder, attributes: [.paragraphStyle: paragraphStyle])
Solution 2
import Foundation
extension String {
func toAttributed(alignment: NSTextAlignment) -> NSAttributedString {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
return toAttributed(attributes: [.paragraphStyle: paragraphStyle])
}
func toAttributed(attributes: [NSAttributedString.Key : Any]? = nil) -> NSAttributedString {
return NSAttributedString(string: self, attributes: attributes)
}
}
Usage of the solution 2
// Way 1
textField.attributedPlaceholder = text.attributedString(alignment: .center)
// Way 2
textField.attributedPlaceholder = "title".attributedString(alignment: .center)
Full sample
Do not forget to add the solution code here
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let textField = UITextField()
textField.borderStyle = .roundedRect
view.addSubview(textField)
//textField.attributedPlaceholder = getAttributedString1()
textField.attributedPlaceholder = getAttributedString2()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 24).isActive = true
textField.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 16).isActive = true
view.safeAreaLayoutGuide.rightAnchor.constraint(equalTo: textField.rightAnchor, constant: 16).isActive = true
}
private func getAttributedString1() -> NSAttributedString {
return "placeholder".toAttributed(alignment: .center)
}
private func getAttributedString2() -> NSAttributedString {
var attributes = [NSAttributedString.Key: Any]()
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
attributes[.paragraphStyle] = paragraphStyle
attributes[.font] = UIFont.systemFont(ofSize: 12, weight: .bold)
attributes[.foregroundColor] = UIColor.black.withAlphaComponent(0.5)
attributes[.underlineStyle] = NSUnderlineStyle.single.rawValue
attributes[.underlineColor] = UIColor.red
return "placeholder".toAttributed(attributes: attributes)
}
}
Results

Changing Placeholder Text Color with Swift

I have a design that implements a dark blue UITextField, as the placeholder text is by default a dark grey colour I can barely make out what the place holder text says.
I've googled the problem of course but I have yet to come up with a solution while using the Swift language and not Obj-c.
Is there a way to change the placeholder text colour in a UITextField using Swift?
You can set the placeholder text using an attributed string. Just pass the color you want to the attributes parameter.
Swift 5:
let myTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 200, height: 30))
myTextField.backgroundColor = .blue
myTextField.attributedPlaceholder = NSAttributedString(
string: "Placeholder Text",
attributes: [NSAttributedString.Key.foregroundColor: UIColor.white]
)
Swift 3:
myTextField.attributedPlaceholder = NSAttributedString(
string: "Placeholder Text",
attributes: [NSAttributedStringKey.foregroundColor: UIColor.white]
)
Older Swift:
myTextField.attributedPlaceholder = NSAttributedString(
string: "Placeholder Text",
attributes: [NSForegroundColorAttributeName: UIColor.white]
)
You can accomplish this quickly, without adding a line of code, using Interface Builder.
Select the UITextField and open the identity inspector on the right:
Click on the plus button and add a new runtime attribute:
placeholderLabel.textColor (Swift 4)
_placeholderLabel.textColor (Swift 3 or less)
Use Color as type and select the color.
That's it.
You wont see the result until you run your app again.
Create UITextField Extension like this:
extension UITextField{
#IBInspectable var placeHolderColor: UIColor? {
get {
return self.placeHolderColor
}
set {
self.attributedPlaceholder = NSAttributedString(string:self.placeholder != nil ? self.placeholder! : "", attributes:[NSAttributedString.Key.foregroundColor: newValue!])
}
}
}
And in your storyboard or .xib. You will see
In Swift 3.0, Use
let color = UIColor.lightText
textField.attributedPlaceholder = NSAttributedString(string: textField.placeholder, attributes: [NSForegroundColorAttributeName : color])
In Siwft 5.0 + Use
let color = UIColor.lightText
let placeholder = textField.placeholder ?? "" //There should be a placeholder set in storyboard or elsewhere string or pass empty
textField.attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [NSAttributedString.Key.foregroundColor : color])
This code is working in Swift3:
yourTextFieldName .setValue(UIColor.init(colorLiteralRed: 80/255, green: 80/255, blue: 80/255, alpha: 1.0), forKeyPath: "_placeholderLabel.textColor")
let me know if you have any issue.
To set the placeholder color once for all the UITextField in your app you can do:
UILabel.appearanceWhenContainedInInstancesOfClasses([UITextField.self]).textColor = UIColor.redColor()
This will set the desired color for all TextField placeholders in the entire app. But it is only available since iOS 9.
There is no appearenceWhenContainedIn....() method before iOS 9 in swift but you can use one of the solutions provided here appearanceWhenContainedIn in Swift
In my case, I use Swift 4
I create extension for UITextField
extension UITextField {
func placeholderColor(color: UIColor) {
let attributeString = [
NSAttributedStringKey.foregroundColor: color.withAlphaComponent(0.6),
NSAttributedStringKey.font: self.font!
] as [NSAttributedStringKey : Any]
self.attributedPlaceholder = NSAttributedString(string: self.placeholder!, attributes: attributeString)
}
}
yourField.placeholderColor(color: UIColor.white)
Xcode 9.2 Swift 4
extension UITextField{
#IBInspectable var placeHolderColor: UIColor? {
get {
return self.placeHolderColor
}
set {
self.attributedPlaceholder = NSAttributedString(string:self.placeholder != nil ? self.placeholder! : "", attributes:[NSAttributedStringKey.foregroundColor: newValue!])
}
}
}
For Swift
Create UITextField Extension
extension UITextField{
func setPlaceHolderColor(){
self.attributedPlaceholder = NSAttributedString(string: self.placeholder!, attributes: [NSForegroundColorAttributeName : UIColor.white])
}
}
If Are you set from storyboard.
extension UITextField{
#IBInspectable var placeHolderColor: UIColor? {
get {
return self.placeHolderColor
}
set {
self.attributedPlaceholder = NSAttributedString(string:self.placeholder != nil ? self.placeholder! : "", attributes:[NSAttributedString.Key.foregroundColor : newValue!])
}
}
}
Swift 4 :
txtControl.attributedPlaceholder = NSAttributedString(string: "Placeholder String...",attributes: [NSAttributedStringKey.foregroundColor: UIColor.gray])
Objective-C :
UIColor *color = [UIColor grayColor];
txtControl.attributedPlaceholder = [[NSAttributedString alloc] initWithString:#"Placeholder String..." attributes:#{NSForegroundColorAttributeName: color}];
Here is my quick implementation for swift 4:
extension UITextField {
func placeholderColor(_ color: UIColor){
var placeholderText = ""
if self.placeholder != nil{
placeholderText = self.placeholder!
}
self.attributedPlaceholder = NSAttributedString(string: placeholderText, attributes: [NSAttributedStringKey.foregroundColor : color])
}
}
use like:
streetTextField?.placeholderColor(AppColor.blueColor)
hope it helps someone!
Swift 3 (probably 2), you can override didSet on placeholder in UITextField subclass to apply attribute on it, this way:
override var placeholder: String? {
didSet {
guard let tmpText = placeholder else {
self.attributedPlaceholder = NSAttributedString(string: "")
return
}
let textRange = NSMakeRange(0, tmpText.characters.count)
let attributedText = NSMutableAttributedString(string: tmpText)
attributedText.addAttribute(NSForegroundColorAttributeName , value:UIColor(white:147.0/255.0, alpha:1.0), range: textRange)
self.attributedPlaceholder = attributedText
}
}
I'm surprised to see how many poor solutions there are here.
Here is a version that will always work.
Swift 4.2
extension UITextField{
#IBInspectable var placeholderColor: UIColor {
get {
return self.attributedPlaceholder?.attribute(.foregroundColor, at: 0, effectiveRange: nil) as? UIColor ?? .lightText
}
set {
self.attributedPlaceholder = NSAttributedString(string: self.placeholder ?? "", attributes: [.foregroundColor: newValue])
}
}
}
TIP: If you change the placeholder text after setting the color- the color will reset.
For Swift 3 and 3.1 this works perfectly fine:
passField.attributedPlaceholder = NSAttributedString(string: "password", attributes: [NSForegroundColorAttributeName: UIColor.white])
For Swift 4.0, X-code 9.1 version or iOS 11 you can use following syntax to have different placeholder color
textField.attributedPlaceholder = NSAttributedString(string: "Placeholder Text", attributes: [NSAttributedStringKey.foregroundColor : UIColor.white])
Just write below code into Appdelegate's didFinishLaunchingWithOptions method use this if you want to change in the whole app written in Swift 4.2
UILabel.appearance(whenContainedInInstancesOf: [UITextField.self]).textColor = UIColor.white
Here am i writing all UIDesignable of UITextField. With the help of this code you can directly access it from UI file Inspector in storyboard
#IBDesignable
class CustomTextField: UITextField {
#IBInspectable var leftImage: UIImage? {
didSet {
updateView()
}
}
#IBInspectable var leftPadding: CGFloat = 0 {
didSet {
updateView()
}
}
#IBInspectable var rightImage: UIImage? {
didSet {
updateView()
}
}
#IBInspectable var rightPadding: CGFloat = 0 {
didSet {
updateView()
}
}
private var _isRightViewVisible: Bool = true
var isRightViewVisible: Bool {
get {
return _isRightViewVisible
}
set {
_isRightViewVisible = newValue
updateView()
}
}
func updateView() {
setLeftImage()
setRightImage()
// Placeholder text color
attributedPlaceholder = NSAttributedString(string: placeholder != nil ? placeholder! : "", attributes:[NSAttributedString.Key.foregroundColor: tintColor])
}
func setLeftImage() {
leftViewMode = UITextField.ViewMode.always
var view: UIView
if let image = leftImage {
let imageView = UIImageView(frame: CGRect(x: leftPadding, y: 0, width: 20, height: 20))
imageView.image = image
// Note: In order for your image to use the tint color, you have to select the image in the Assets.xcassets and change the "Render As" property to "Template Image".
imageView.tintColor = tintColor
var width = imageView.frame.width + leftPadding
if borderStyle == UITextField.BorderStyle.none || borderStyle == UITextField.BorderStyle.line {
width += 5
}
view = UIView(frame: CGRect(x: 0, y: 0, width: width, height: 20))
view.addSubview(imageView)
} else {
view = UIView(frame: CGRect(x: 0, y: 0, width: leftPadding, height: 20))
}
leftView = view
}
func setRightImage() {
rightViewMode = UITextField.ViewMode.always
var view: UIView
if let image = rightImage, isRightViewVisible {
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
imageView.image = image
// Note: In order for your image to use the tint color, you have to select the image in the Assets.xcassets and change the "Render As" property to "Template Image".
imageView.tintColor = tintColor
var width = imageView.frame.width + rightPadding
if borderStyle == UITextField.BorderStyle.none || borderStyle == UITextField.BorderStyle.line {
width += 5
}
view = UIView(frame: CGRect(x: 0, y: 0, width: width, height: 20))
view.addSubview(imageView)
} else {
view = UIView(frame: CGRect(x: 0, y: 0, width: rightPadding, height: 20))
}
rightView = view
}
#IBInspectable public var borderColor: UIColor = UIColor.clear {
didSet {
layer.borderColor = borderColor.cgColor
}
}
#IBInspectable public var borderWidth: CGFloat = 0 {
didSet {
layer.borderWidth = borderWidth
}
}
#IBInspectable public var cornerRadius: CGFloat = 0 {
didSet {
layer.cornerRadius = cornerRadius
}
}
#IBInspectable public var bottomBorder: CGFloat = 0 {
didSet {
borderStyle = .none
layer.backgroundColor = UIColor.white.cgColor
layer.masksToBounds = false
// layer.shadowColor = UIColor.gray.cgColor
layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
layer.shadowOpacity = 1.0
layer.shadowRadius = 0.0
}
}
#IBInspectable public var bottomBorderColor : UIColor = UIColor.clear {
didSet {
layer.shadowColor = bottomBorderColor.cgColor
layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
layer.shadowOpacity = 1.0
layer.shadowRadius = 0.0
}
}
/// Sets the placeholder color
#IBInspectable var placeHolderColor: UIColor? {
get {
return self.placeHolderColor
}
set {
self.attributedPlaceholder = NSAttributedString(string:self.placeholder != nil ? self.placeholder! : "", attributes:[NSAttributedString.Key.foregroundColor: newValue!])
}
}
}
Use like this in Swift,
let placeHolderText = textField.placeholder ?? ""
let str = NSAttributedString(string:placeHolderText!, attributes: [NSAttributedString.Key.foregroundColor :UIColor.lightGray])
textField.attributedPlaceholder = str
In Objective C
NSString *placeHolder = [textField.placeholder length]>0 ? textField.placeholder: #"";
NSAttributedString *str = [[NSAttributedString alloc] initWithString:placeHolder attributes:#{ NSForegroundColorAttributeName : [UIColor lightGrayColor] }];
textField.attributedPlaceholder = str;
In my case, I had to make the placeholder into black color. The name of my UITextField is passwordText. Below code is tested in Swift 5 and is working fine for me. I also had an existing text for the corresponding placeholder.
let placeholderColor = UIColor.black
passwordText.attributedPlaceholder = NSAttributedString(string: passwordText.placeholder!, attributes: [NSAttributedString.Key.foregroundColor : placeholderColor])
crubio's answer update for Swift 4
Select the UITextField and open the identity inspector on the right:
Click on the plus button and add a new runtime attribute: placeholderLabel.textColor (instead of _placeholderLabel.textColor)
Use Color as type and select the color.
If you run your project, you will see the changes.
For swift 4.2 and above you can do it as below:
textField.attributedPlaceholder = NSAttributedString(string: "Placeholder Text", attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])
In my case, I have done following:
extension UITextField {
#IBInspectable var placeHolderColor: UIColor? {
get {
if let color = self.attributedPlaceholder?.attribute(.foregroundColor, at: 0, effectiveRange: nil) as? UIColor {
return color
}
return nil
}
set (setOptionalColor) {
if let setColor = setOptionalColor {
let string = self.placeholder ?? ""
self.attributedPlaceholder = NSAttributedString(string: string , attributes:[NSAttributedString.Key.foregroundColor: setColor])
}
}
}
}
extension UITextField{
#IBInspectable var placeHolderColor: UIColor? {
get {
return self.placeHolderColor
}
set {
self.attributedPlaceholder = NSAttributedString(string:self.placeholder != nil ?
self.placeholder! : "",
attributes:[NSAttributedString.Key.foregroundColor : newValue!])
}
}
}
For Swift
func setPlaceholderColor(textField: UITextField, placeholderText: String) {
textField.attributedPlaceholder = NSAttributedString(string: placeholderText, attributes: [NSForegroundColorAttributeName: UIColor.pelorBlack])
}
You can use this;
self.setPlaceholderColor(textField: self.emailTextField, placeholderText: "E-Mail/Username")
It is more about personalize your textField but anyways I'll share this code got from another page and made it a little better:
import UIKit
extension UITextField {
func setBottomLine(borderColor: UIColor, fontColor: UIColor, placeHolderColor:UIColor, placeHolder: String) {
self.borderStyle = UITextBorderStyle.none
self.backgroundColor = UIColor.clear
let borderLine = UIView()
let height = 1.0
borderLine.frame = CGRect(x: 0, y: Double(self.frame.height) - height, width: Double(self.frame.width), height: height)
self.textColor = fontColor
borderLine.backgroundColor = borderColor
self.addSubview(borderLine)
self.attributedPlaceholder = NSAttributedString(
string: placeHolder,
attributes: [NSAttributedStringKey.foregroundColor: placeHolderColor]
)
}
}
And you can use it like this:
self.textField.setBottomLine(borderColor: lineColor, fontColor: fontColor, placeHolderColor: placeHolderColor, placeHolder: placeHolder)
Knowing that you have an UITextField connected to a ViewController.
Source: http://codepany.com/blog/swift-3-custom-uitextfield-with-single-line-input/
For Objective C:
UIColor *color = [UIColor colorWithRed:0.44 green:0.44 blue:0.44 alpha:1.0];
emailTextField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:#"Friend's Email" attributes:#{NSForegroundColorAttributeName: color}];
For Swift:
emailTextField.attributedPlaceholder = NSAttributedString(string: "Friend's Email",
attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])
Objective C code for changing placeholder text color.
First import this objc/runtime class -
#import <objc/runtime.h>
then replace your textfield name -
Ivar ivar = class_getInstanceVariable([UITextField class], "_placeholderLabel");
UILabel *placeholderLabel = object_getIvar(YourTxtField, ivar);
placeholderLabel.textColor = [UIColor whiteColor];
for iOS13
+(void)ChangeplaceholderColor :(UITextField *)TxtFld andColor:(UIColor*)color {
NSMutableAttributedString *placeholderAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:TxtFld.attributedPlaceholder];
[placeholderAttributedString addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(0, [placeholderAttributedString length])];
TxtFld.attributedPlaceholder = placeholderAttributedString;
}
Use this for adding an attributed placeholder:
let attributes : [String : Any] = [ NSForegroundColorAttributeName: UIColor.lightGray,
NSFontAttributeName : UIFont(name: "Helvetica Neue Light Italic", size: 12.0)!
]
x_textfield.attributedPlaceholder = NSAttributedString(string: "Placeholder Text", attributes:attributes)
For Swift 4
txtField1.attributedPlaceholder = NSAttributedString(string: "-", attributes: [NSAttributedStringKey.foregroundColor: UIColor.white])

Resources