Swift - UITextView text is getting cut when applying custom font - ios

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.

Related

How to check current font size of UILabel?

I have 3 UILabels and I want to set same (the smallest one from all of 3 possibilities) font for all of them. What is the problem? I don't know how to check the current font - each of UILabels use Autoshrink with minimal font scale and lines amount equaled to 0. The text of UILabels is set in ViewDidLoad() method (there are many combinations of possible label texts).
I tried to get the current font size with UILabel.font.pointSize property (called in viewDidAppear() method) and than compare all of them. The problem is that that UILabel.font.pointSize returns not current value of UILabel text font size (after Autoshrink has been done) but the value that is set in storyboard.
I'm totally out of ideas so thanks for the help!
Greetings, John
use this extention
extension String {
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return ceil(boundingBox.height)
}
}
get height
height = strDesc.height(withConstrainedWidth: UIScreen.main.bounds.size.width - 160, font: UIFont.systemFont(ofSize: 14.0))
This is one way to get the current size of the UILabel pointsize although I know of more ways if this does not work. This is the cleanest and fastest. See example and extension included.
import UIKit
class ViewController: UIViewController {
lazy var label1 : UILabel = {
let lbl = UILabel(frame: CGRect(x: 20, y: 80, width: self.view.bounds.width - 40, height: 40))
lbl.text = "This is some large text to make it fit to size with a big font size"
lbl.font = UIFont.systemFont(ofSize: 50, weight: .bold)
lbl.textColor = .black
lbl.minimumScaleFactor = 0.01
lbl.adjustsFontSizeToFitWidth = true
lbl.numberOfLines = 0
return lbl
}()
lazy var label2 : UILabel = {
let lbl = UILabel(frame: CGRect(x: 20, y: label1.frame.maxY + 5, width: self.view.bounds.width - 40, height: 40))
lbl.text = "This is one line"
lbl.font = UIFont.systemFont(ofSize: 20, weight: .bold)
lbl.textColor = .black
lbl.minimumScaleFactor = 0.01
lbl.adjustsFontSizeToFitWidth = true
lbl.numberOfLines = 0
return lbl
}()
lazy var label3 : UILabel = {
let lbl = UILabel(frame: CGRect(x: 20, y: label2.frame.maxY + 10, width: self.view.bounds.width - 40, height: 80))
lbl.text = "This is some large text to make it fit to size with a big font size"
lbl.font = UIFont.systemFont(ofSize: 100, weight: .bold)
lbl.textColor = .black
lbl.minimumScaleFactor = 0.01
lbl.adjustsFontSizeToFitWidth = true
lbl.numberOfLines = 0
return lbl
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.addSubview(label1)
self.view.addSubview(label2)
self.view.addSubview(label3)
var minSize : CGFloat = .greatestFiniteMagnitude
for sub in self.view.subviews{
if let lbl = sub as? UILabel{
//get the size
let font = lbl.adjustedFont()
print("the size is \(font.pointSize)")
minSize = min(font.pointSize,minSize)
}
}
print("the minimum for all fonts is \(minSize)")
print("i am going to delay for 3 seconds and then reset all the labels to the minimum size :)")
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3.0) {
for sub in self.view.subviews{
if let lbl = sub as? UILabel{
lbl.font = lbl.font.withSize(minSize)
}
}
}
}
}
extension UILabel{
func adjustedFont()->UIFont {
guard let txt = text else {
return self.font
}
let attributes: [NSAttributedString.Key: Any] = [.font: self.font]
let attributedString = NSAttributedString(string: txt, attributes: attributes)
let drawingContext = NSStringDrawingContext()
drawingContext.minimumScaleFactor = self.minimumScaleFactor
attributedString.boundingRect(with: bounds.size,
options: [.usesLineFragmentOrigin,.usesFontLeading],
context: drawingContext)
let fontSize = font.pointSize * drawingContext.actualScaleFactor
return font.withSize(CGFloat(floor(Double(fontSize))))
}
}
Example in Action
What I've found is that inside viewDidLoad() your constraints are not fully defined yet. You can try to do these calculations in another method for example viewWillAppear() or any other that suits you and is executed after viewDidLoad().

resizing UILabels based on total width of text

How would I go about predicting the required width of a UILabel based on it's font size and number of characters in the label's text.
I have seen a few examples of this being done, however they are all in objective-c not swift 3.0.
I found this method but it's in objective-c and I'm having trouble implementing it.
CGFloat width = [label.text sizeWithFont:[UIFont systemFontOfSize:17.0f]].width;
Any suggestions?
If Want to Make size of UILabel Based on TextSize and TextLength then use
intrinsicContentSize.
Below is sample code for that:
lblDemo.frame.size = lblDemo.intrinsicContentSize
Here lblDemo is IBOutlet of UILabel.
override func viewDidLoad() {
super.viewDidLoad()
let screenSize = UIScreen.main.bounds
let screenWidth = screenSize.width
let text = "Size To Fit Tutorial"
let font : UIFont!
switch UIDevice.current.userInterfaceIdiom {
case .pad:
font = UIFont(name: "Helvetica", size: 35)
case .phone:
font = UIFont(name: "Helvetica", size: 50)
default:
font = UIFont(name: "Helvetica", size: 24)
}
let yourHeight = heightForLabel(text: text, font: font, width:
screenWidth)
let yourLabel : UILabel = UILabel(Frame : CGRect(x:0 ,y:0
,width:screenWidth ,height:yourHeight))
yourLabel.backgroundColor = UIColor.black
self.view.addSubviews(yourLabel)
}
//Self Sizing height ....
func heightForLabel(text:String, font:UIFont, width:CGFloat) -> CGFloat{
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width:
width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byCharWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
Hope, it helps
You can cast the string you are setting the label's text value to type NSString.
guard let labelText = label.text else { return }
let castString = labelText as NSString
let size: CGSize = castString.size(attributes: [NSFontAttributeName : UIFont.systemFontSize])
//you now can use size.width to apply to a desired view
You want to get width of label based on text entered. I think you will find appropriate solution here
How to calculate UILabel width based on text length?
Hope, it helps

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

UILabel text truncation vs. line breaks in text

I have a UILabel that is put as titleView in the navigation bar. I want it to have 2 lines, where the first line can be truncated and the second is center aligned.
In code it looks more less like this:
let label = UILabel()
let text = NSAttributedString(string: "Long long long text\nsecond line")
label.attributedText = text
label.textAlignment = .Center
label.numberOfLines = 0
label.lineBreakMode = .ByTruncatingTail
label.sizeToFit()
self.navigationItem.titleView = label
The effect in case of the first line text is not exceeding available
space is like this:
It's pretty good, but when the first line text is longer than:
let text = NSAttributedString(string: "Very very very very very long text\nsecond line")
I want to achieve like below.
How it can be done? I experimented with numberOfLines and lineBreakMode but it's not worked.
change your line breakmode to ByTruncatingMiddle instead of ByTruncatingTail. Something like below,
label.lineBreakMode = .ByTruncatingMiddle
Hope this will help :)
Navigation Tittle with sub-Tittle (Multiline Navigation Tittle)
Use NSMutableAttributedString with UITextView instead of UILabel
(because, if tittle is large then UILabel lineBreakMode with .byTruncatingTail is not working for first line in UILabel)
func multilineNavigation(title:String,subTitle:String) {
DispatchQueue.main.async {
let titleAttributedStr = NSMutableAttributedString(string: title, attributes: [NSAttributedStringKey.foregroundColor: UIColor.orange,NSAttributedStringKey.font: UIFont(name: "Helvetica Neue", size: 17.0) ?? UIFont()])
let subTitleAttributedStr = NSMutableAttributedString(string: "\n\(subTitle)", attributes: [NSAttributedStringKey.foregroundColor: UIColor.green,NSAttributedStringKey.font: UIFont(name: "Helvetica Neue", size: 12.0) ?? UIFont()])
titleAttributedStr.append(subTitleAttributedStr)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 1
paragraphStyle.lineBreakMode = .byTruncatingTail
titleAttributedStr.addAttribute(.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, titleAttributedStr.length))
let textView = UITextView()
textView.attributedText = titleAttributedStr
textView.backgroundColor = .clear
textView.isUserInteractionEnabled = false
textView.textContainerInset = .zero
textView.textAlignment = .center
textView.frame = CGRect(x: 0, y: 0, width: textView.intrinsicContentSize.width, height: 44)
self.navigationItem.titleView = textView
}
}

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