Placeholder text not centered in iOS - ios

I have created text field with Rounded Corners. All is good with the position of the cursor and also when i type the text. But the Placeholder text is off. Is there a way for the placeholder position to follow the Text field.
Below code overrides from the UITextField functions to reposition the cursor.
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: 0 + textOffset,
y: 0 + (textOffset / 2),
width: self.frame.width - textOffset,
height: self.frame.height + textOffset)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: 0 + textOffset,
y: 0 + (textOffset / 2),
width: self.frame.width - textOffset,
height: self.frame.height + textOffset)

Use this override method to set placeholderRect
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, paddingInsets)
}

You can use attributedPlaceholder paragraph styles you can center the placeholder in a UITextField.
let textField = UITextField(frame: CGRect(x: 0, y: 100, width: self.view.frame.size.width, height: 60))
textField.backgroundColor = UIColor.gray
let centeredParagraphStyle = NSMutableParagraphStyle()
centeredParagraphStyle.alignment = .center
let attributedPlaceholder = NSAttributedString(string: "Placeholder", attributes: [NSAttributedStringKey.paragraphStyle: centeredParagraphStyle])
textField.attributedPlaceholder = attributedPlaceholder

What worked for me was creating baselineOffset attribute and then setting the attributedPlaceholder.
let attributes = [NSAttributedString.Key.baselineOffset : NSNumber(2.0)]
myTextField.attributedPlaceholder = NSAttributedString(string: "Placeholder", attributes: attributes)

Related

How to vertically and horizontally align text in SkyFloatingLabelTextField?

I have use SkyFloatingLabelTextField and I want to vertically and horizontally center align text.
I have to write code but it aligns text only horizontally not vertically.
what I have tried is
var rightButton = UIButton(frame: CGRect(x: 0, y: 0, width: 25, height: 25))
var imageNew = UIImage(named: "rightArrow")!
rightButton.contentMode = .scaleAspectFit
rightButton.setImage(imageNew, for: .normal)
rightButton.setImage(imageNew, for: .selected)
rightButton.contentVerticalAlignment = .center
rightButton.contentHorizontalAlignment = .center
selectTradeTxt.rightView = rightButton
selectTradeTxt.rightView?.frame = self.selectTradeTxt.rightViewRect(forBounds: self.selectTradeTxt.bounds)
selectTradeTxt.rightViewMode = .always
selectTradeTxt.textColor = .white
selectTradeTxt.addRoundCorner(7)
// i have tried this
// selectTradeTxt.contentHorizontalAlignment = .center
selectTradeTxt.contentVerticalAlignment = .center
selectTradeTxt.textAlignment = .center
You have to change frame y position as bellow override function in SkyFloatingLabelTextField.swift file
// MARK: - UITextField text/placeholder positioning overrides
/**
Calculate the rectangle for the textfield when it is not being edited
- parameter bounds: The current bounds of the field
- returns: The rectangle that the textfield should render in
*/
override open func textRect(forBounds bounds: CGRect) -> CGRect {
let superRect = super.textRect(forBounds: bounds)
let titleHeight = self.titleHeight()
let rect = CGRect(
x: superRect.origin.x,
y: titleHeight + 2,
width: superRect.size.width,
height: superRect.size.height - titleHeight - selectedLineHeight
)
return rect
}
/**
Calculate the rectangle for the textfield when it is being edited
- parameter bounds: The current bounds of the field
- returns: The rectangle that the textfield should render in
*/
override open func editingRect(forBounds bounds: CGRect) -> CGRect {
let superRect = super.editingRect(forBounds: bounds)
let titleHeight = self.titleHeight()
let rect = CGRect(
x: superRect.origin.x,
y: titleHeight + 2,
width: superRect.size.width,
height: superRect.size.height - titleHeight - selectedLineHeight
)
return rect
}
/**
Calculate the rectangle for the placeholder
- parameter bounds: The current bounds of the placeholder
- returns: The rectangle that the placeholder should render in
*/
override open func placeholderRect(forBounds bounds: CGRect) -> CGRect {
let rect = CGRect(
x: 0,
y: self.isEditing ? titleHeight() : titleHeight() - 8,
width: bounds.size.width,
height: bounds.size.height - titleHeight() - selectedLineHeight
)
return rect
}
// MARK: - Positioning Overrides
/**
Calculate the bounds for the title label. Override to create a custom size title field.
- parameter bounds: The current bounds of the title
- parameter editing: True if the control is selected or highlighted
- returns: The rectangle that the title label should render in
*/
open func titleLabelRectForBounds(_ bounds: CGRect, editing: Bool) -> CGRect {
if editing {
return CGRect(x: 0, y: 10, width: bounds.size.width, height: titleHeight())
}
return CGRect(x: 0, y: titleHeight(), width: bounds.size.width, height: titleHeight())
}

Border width and placeholder in custom UITextField

I want to make this TextField
So I write this class
class UnderLineTextField:UITextField{
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.darkgray().cgColor
border.frame = CGRect(x: 0, y: frame.size.height - width, width: frame.size.width, height: frame.size.height)
textColor = UIColor.gold()
backgroundColor = UIColor.clear
border.borderWidth = width
layer.addSublayer(border)
layer.masksToBounds = true
attributedPlaceholder = NSAttributedString(string: "",
attributes: [NSAttributedStringKey.foregroundColor: UIColor.darkgray()])}
}
But there are two problems
The underline is not equal to TextField, if I add more width width: frame.size.width + 500, the problem can be fixed, but why? what is the correct value I should pass to width:?
attributedPlaceholder will replace the placeholder I set in xib, how can I change placeholder without adding empty string?
The underline is not equal to TextField, if I add more width width: frame.size.width + 500, the problem can be fixed, but why? what is the correct value I should pass to width:?
You should put your draw underline code to draw(_ rect: CGRect) instead of init. Because of you using autolayout, so the width, that you got in init is difference with the width that you can see when run app.
attributedPlaceholder will replace the placeholder I set in xib, how can I change placeholder without adding empty string?
You can redraw the attributedPlaceholder base on your placeholder in draw(_ rect: CGRect), too
attributedPlaceholder = NSAttributedString(
string: self.placeholder,
attributes: [NSAttributedStringKey.foregroundColor: UIColor.darkgray()]
)
It seems your code is ok.
use below code for setting placeholder:
class UnderLineTextField:UITextField{
#IBInspectable var borderColor: UIColor = UIColor.white {
didSet {
layer.borderColor = borderColor.cgColor
}
}
#IBInspectable var placeHolderText: String = "default place holder" {
didSet {
attributedPlaceholder = NSAttributedString(string: placeHolderText,
attributes: [NSAttributedStringKey.foregroundColor: UIColor.darkGray])}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.darkGray.cgColor
border.frame = CGRect(x: 0, y: frame.size.height - width, width: frame.size.width, height: frame.size.height)
textColor = UIColor.lightGray
backgroundColor = UIColor.clear
border.borderWidth = width
layer.addSublayer(border)
layer.masksToBounds = true
attributedPlaceholder = NSAttributedString(string: placeHolderText,
attributes: [NSAttributedStringKey.foregroundColor: UIColor.darkGray])}
}
and set your placeholder in storyboard:
The result will look like below:
For UITextField underline use this one...
let border = CALayer()
let width = CGFloat(1.0)
border.borderColor = UIColor.gray.cgColor
border.frame = CGRect(x: 0, y: textField.frame.size.height - width, width: textField.frame.size.width, height: textField.frame.size.height)
border.borderWidth = width
textField.layer.addSublayer(border)
textField.layer.masksToBounds = true
Hey already lot of answers :), let's see if this detailed answer can help you achieve more:
I prefer using extensions over inheritance if possible.
extension UITextField {
func setTextColor(_ color: UIColor, font: UIFont) {
self.textColor = color
self.font = font
}
func setBottomBorder(with color: UIColor, width: CGFloat) {
self.borderStyle = .none
self.layer.backgroundColor = UIColor.white.cgColor // bg color of your choice
self.layer.masksToBounds = false
self.layer.shadowColor = color.cgColor
self.layer.shadowOffset = CGSize(width: 0.0, height: width)
self.layer.shadowOpacity = 1.0
self.layer.shadowRadius = 0.0
}
func setPlaceHolderAttributes(placeHolderText : String, colour : UIColor , font : UIFont){
self.attributedPlaceholder = NSAttributedString(string:placeHolderText, attributes:[NSAttributedStringKey.foregroundColor: colour , NSAttributedStringKey.font : font])
}
}
//MARK: To give text insets
class MyTextField: UITextField {
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect.init(x:10, y:2, width:bounds.width-20, height:bounds.height - 4)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return textRect(forBounds: bounds)
}
}
And I prefer to configure UI from Code, it will fasten up your coding speed and achieve doing project wise change from one place, so you can do it from code like:
let font: UIFont = UIFont.systemFont(ofSize: 14.0)
let placeHolderTextColor: UIColor = UIColor.brown
let textColor: UIColor = UIColor.darkText
nameTextField.setBottomBorder(with: UIColor.darkGray, width: 1.0)
passwordTextField.setBottomBorder(with: UIColor.darkGray, width: 1.0)
nameTextField.setPlaceHolderAttributes(placeHolderText: "Name", colour: placeHolderTextColor, font: font)
nameTextField.setTextColor(textColor, font: font)
passwordTextField.setPlaceHolderAttributes(placeHolderText: "Password", colour: placeHolderTextColor, font: font)
passwordTextField.setTextColor(textColor, font: font)
Hope this helps :)

single border for UITextField within a UIcollectionViewCell (swift 3 xcode)

I'm trying to apply a single bottom border to a textField that sits within one of my collectionViewCells. Here is the code:
class AddressCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
func basicTextField(placeHolderString: String) -> UITextField {
let textField = UITextField()
textField.font = UIFont.boldSystemFont(ofSize: 12)
textField.attributedPlaceholder = NSAttributedString(string: placeHolderString, attributes:[NSForegroundColorAttributeName: UIColor.lightGray, NSFontAttributeName: UIFont.boldSystemFont(ofSize: 12)])
textField.backgroundColor = UIColor.white
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
backgroundColor = UIColor.white
layer.addBorder(edge: UIRectEdge.bottom, color: .black, thickness: 0.5)
let streetTextfield = basicTextField(placeHolderString: "street")
addSubview(streetTextfield)
}
}
I am using an extension that enables me to apply a single border, which has worked great so far:
extension CALayer {
func addBorder(edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer()
switch edge {
case UIRectEdge.top:
border.frame = CGRect.init(x: 0, y: 0, width: frame.width, height: thickness)
break
case UIRectEdge.bottom:
border.frame = CGRect.init(x: 0, y: frame.height - thickness, width: frame.width, height: thickness)
break
case UIRectEdge.left:
border.frame = CGRect.init(x: 0, y: 0, width: thickness, height: frame.height)
break
case UIRectEdge.right:
border.frame = CGRect.init(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
break
default:
break
}
border.backgroundColor = color.cgColor;
self.addSublayer(border)
}
}
When i simply add a borderWidth to the textfield like this:
textField.layer.borderWidth = 0.5
I get a border and it renders fine. However, when i apply the extension to add a bottom border, like this:
textField.layer.addBorder(edge: UIRectEdge.bottom, color: .black, thickness: 0.5)
the border doesn't apply for some reason.
I'm not sure about the extension, but I have a working solution for a TextField with a bottom border.
basically create a class BottomBorderedTextField subclassing UITextField and insert the following code:
class BottomBorderedTextField: UITextField {
override func draw(_ rect: CGRect) {
super.draw(rect)
//this is the color of the bottom border. Change to whatever you what
let color: UIColor = UIColor.rgb(red: 230, green: 230, blue: 230)
let bottomBorder = CALayer()
bottomBorder.frame = CGRect(x: 0, y: bounds.size.height - 1, width: bounds.size.width, height: 2)
bottomBorder.backgroundColor = color.cgColor
self.layer.addSublayer(bottomBorder)
}
}
Then on your basicTextField function set the return type to the BottomBorderedTextField class you just made. so your new code will look like:
func basicTextField(placeHolderString: String) -> BottomBorderedTextField {
let textField = BottomBorderedTextField()
textField.font = UIFont.boldSystemFont(ofSize: 12)
textField.attributedPlaceholder = NSAttributedString(string: placeHolderString, attributes:[NSForegroundColorAttributeName: UIColor.lightGray, NSFontAttributeName: UIFont.boldSystemFont(ofSize: 12)])
textField.backgroundColor = UIColor.white
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}
I wrote a UIView extension that accomplishes the same thing:
extension UIView {
func addBottomBorder(width: CGFloat, color: UIColor, alpha: CGFloat) {
let border = CALayer()
let width = width
border.borderColor = color.withAlphaComponent(alpha).cgColor
border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: self.frame.size.height)
border.borderWidth = width
self.layer.addSublayer(border)
self.layer.masksToBounds = true
}
}
Usage:
usernameField.addBottomBorder(width: 2.0, color: UIColor.white, alpha: 0.5)
Also, seems within setupViews() you're calling:
layer.addBorder... //this is being called on the collection view cells layer
As opposed to:
streetTextfield.layer.addBorder...

change bottom line border of uitextfield swift

I'm trying to change border properties with the following code:
class SimpleTextField: UITextField, UITextFieldDelegate {
override func layoutSubviews() {
super.layoutSubviews()
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.black.cgColor
border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: self.frame.size.height)
border.borderWidth = width
self.layer.addSublayer(border)
self.layer.masksToBounds = true
self.delegate = self
}
func textFieldDidBeginEditing(_ textField: UITextField) {
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.green.cgColor
border.frame = CGRect(x: 0, y: textField.frame.size.height - width, width: textField.frame.size.width, height: textField.frame.size.height)
border.borderWidth = width
textField.layer.addSublayer(border)
textField.layer.masksToBounds = true
}
func textFieldDidEndEditing(_ textField: UITextField) {
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.black.cgColor
border.frame = CGRect(x: 0, y: textField.frame.size.height - width, width: textField.frame.size.width, height: textField.frame.size.height)
border.borderWidth = width
textField.layer.addSublayer(border)
textField.layer.masksToBounds = true
}
}
I wrote code in layoutSubviews() function as a default appearance for textField. I used textFieldDidBeginEditing() and textFieldDidEndEditing() functions for changing bottom border color. If I use the code layoutSubviews() the border color won't be changed at all but if I remove the code that I use as default appearance, border color will change but I don't have default border as the first time when text field is appeared.
Don't create new layer every time you start/end editing the text field. Instead, reuse it: make it a property and then just update when needed accordingly.
The default appearance you can set at the same point where the text field itself and the border are created, e.g.:
let textField = UITextField(frame: CGRect(x: 100.0, y: 100.0, width: 200.0, height: 50.0))
let border = CALayer()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(textField)
textField.layer.addSublayer(border)
textField.delegate = self
updateBorder(textField: textField, color: UIColor.black, width: 2.0)
}
func updateBorder(textField: UITextField, color: UIColor, width: CGFloat) -> Void {
border.backgroundColor = color.cgColor
border.frame = CGRect(x: 0.0, y: textField.frame.size.height - width, width: textField.frame.size.width, height: width);
}
func textFieldDidBeginEditing(_ textField: UITextField) {
updateBorder(textField: textField, color: UIColor.green, width: 2.0)
}
func textFieldDidEndEditing(_ textField: UITextField) {
updateBorder(textField: textField, color: UIColor.black, width: 2.0)
}

set the padding of a text field using swift in xcode

How to create some space at the beginning of a text field using swift?
I looked at the post
padding of text field
I don't understand what the subclass is doing and how do I use that class to padding.
Thank you very much
https://stackoverflow.com/a/27066764/846780
This answer is very clear,
If you subclass UITextField you can override textRectForBounds, editingRectForBounds and placeholderRectForBounds. These methods just allow you to add a rect (frame) to your textfield's label.
newBounds method create the rect (frame) that will be added to textfield's label.
Finally your padding is: let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5);
Now you have a custom UITextField that has a custom padding.
If you create your new subClass like this class MyTextField: UITextField for example, you only need to change the class of the UITextField that you've added into IB file.
Complementing the answer of klevison-matias this is the code I use when I want to add a padding to my TextField in Swift 3
//UITextField : override textRect, editingRect
class LeftPaddedTextField: UITextField {
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 10, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 10, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
}
Then in my TextField I use in this way:
let emailTextField: LeftPaddedTextField = {
let textField = LeftPaddedTextField()
textField.placeholder = "Enter email"
textField.layer.borderColor = UIColor.lightGray.cgColor
textField.layer.borderWidth = 1
textField.keyboardType = .emailAddress
return textField
}()
let passwordTextField: LeftPaddedTextField = {
let textField = LeftPaddedTextField()
textField.placeholder = "Enter password"
textField.layer.borderColor = UIColor.lightGray.cgColor
textField.layer.borderWidth = 1
textField.isSecureTextEntry = true
return textField
}()
Create TextField outlet and use following code. Say "nameTextField" has to add padding.
let paddingView = UIView(frame: CGRectMake(x: 0, y: 0, width: 30, height: 30))
nameTextField.leftView = paddingView
nameTextField.leftViewMode = .always
nameTextField.placeholder = "Enter Name"
You can add Image in paddingView.
Based on #Jorge Casariego's answer I came up with this solution.
You can set PaddedTextField class and the desired padding through the Interface Builder!
class PaddedTextField: UITextField {
#IBInspectable var padding: CGFloat = 0
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + padding, y: bounds.origin.y, width: bounds.width - padding * 2, height: bounds.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + padding, y: bounds.origin.y, width: bounds.width - padding * 2, height: bounds.height)
}
}
full code sample:
make sure your TextField points to RoundedTextField via Story board
import UIKit
class RoundedTextField: UITextField {
override func awakeFromNib() {
// add rounded corner
self.layer.cornerRadius = 15.0
self.clipsToBounds = false
super.awakeFromNib()
}
// For the padding from the left
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 15.0, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 15.0, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
}

Resources