UITextField Standard Style programmatically - ios

When I create a UITextField using storyboard, it looks like the image below. However, when I create a UITextField programmatically it has absolutely no style. I know that I can apply custom styles to the text field, but is there an easy way to get this standard style when creating the text field programmatically?

Something like this:
let t = UITextField()
t.frame = CGRect(x: 10, y: 20, width: self.view.frame.width - 20, height: 40)
t.layer.cornerRadius = 5
t.layer.borderColor = UIColor.lightGray.cgColor
t.layer.borderWidth = 1
t.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: t.frame.height))
t.leftViewMode = .always
t.rightView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: t.frame.height))
t.rightViewMode = .always
t.clearButtonMode = .whileEditing
self.view.addSubview(t)
EDIT:
Add this class below somewhere such that it is easily / globally accessible.
class StyledTextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.cornerRadius = 5
self.layer.borderColor = UIColor.lightGray.cgColor
self.layer.borderWidth = 1
self.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: t.frame.height))
self.leftViewMode = .always
self.rightView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: t.frame.height))
self.rightViewMode = .always
self.clearButtonMode = .whileEditing
}
}
Then you can call this UITextField from where ever you want as follows
let t = StyledTextField()
t.frame = CGRect(x: 10, y: 20, width: self.view.frame.width - 20, height: 40)
self.view.addSubview(t)
EDIT 2:
Use UIEdgeInsets to get padding on all four sides.
class StyledTextField: UITextField {
let insetConstant = UIEdgeInsets(top: 4, left: 10, bottom: 4, right: 10)
override func textRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, insetConstant)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, insetConstant)
}
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, insetConstant)
}
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.cornerRadius = 5
self.layer.borderColor = UIColor(white: 2/3, alpha: 0.5).cgColor
self.layer.borderWidth = 1
self.clearButtonMode = .whileEditing
self.keyboardType = UIKeyboardType.decimalPad
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

You can add borderStyle as .roundedRect and use White background. Something like this:
class MyCustmUITextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
self.borderStyle = .roundedRect
self.backgroundColor = .white
}
}

You can create a subclass from UITextField to serve as your custom text field.
Following this, you need only to instantiate your custom class and then you're good to go.
Something like this:
class MyCustmUITextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.cornerRadius = 5
self.layer.borderColor = UIColor.black
self.font = UIFont.systemFont(ofSize: 20)
self.adjustsFontSizeToFitWidth = true
// then add whatever styles you wish
}
}
From there all you need is to create a new instance of MyCustomUITextField

Related

Subclass UINavigationBar SWIFT

I want to pose my problem with the hope that someone can help me:
I created a subclass of UINavigationBar, adding an image as a background.
here is the code:
class NavigationBarN: UINavigationBar {
let customHeight: CGFloat = UIScreen.main.bounds.height / 8
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
translatesAutoresizingMaskIntoConstraints = true
self.barStyle = UIBarStyle.black
self.tintColor = .white
}
override init(frame: CGRect) {
super.init(frame: frame)
translatesAutoresizingMaskIntoConstraints = true
self.barStyle = UIBarStyle.black
self.tintColor = .white
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: customHeight)
}
var i = 0
override open func layoutSubviews() {
super.layoutSubviews()
frame = CGRect(x: frame.origin.x, y: 0, width: frame.size.width, height: customHeight) // problem here
for subview in self.subviews {
var stringFromClass = NSStringFromClass(subview.classForCoder)
if stringFromClass.contains("BarBackground") {
subview.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
let imageViewBackground = UIImageView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: customHeight))
imageViewBackground.image = UIImage(named: “Image”1)
imageViewBackground.contentMode = .scaleToFill
subview.addSubview(imageViewBackground)
}
stringFromClass = NSStringFromClass(subview.classForCoder)
if stringFromClass.contains("BarContent") {
let centerY = subview.frame.heigh
subview.frame = CGRect(x: subview.frame.origin.x, y: centerY, width: subview.frame.width, height: subview.frame.height)
}
}
}
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
}
Up to iOS 11, it works without problems since iOS 12 the problems begin, the subclass enters an infinite loop. However the infinite loop occurs only when I try to initialize a new VC through the "navigationController? .PushViewController" function, otherwise it works.
The line of code causing the loop apparently is:
frame = CGRect(x: frame.origin.x, y: 0, width: frame.size.width, height: customHeight)
But removing it the navigation bar is not created correctly.
Anyone have any solution?
Thank You
You shouldn't change your frame in layoutSubviews – you should only be laying out your subviews. Changing the size of the frame in layoutSubviews couples the layout and sizing of the view, which you shouldn't do.
It's likely that under the hood, UINavigationBar is calling setNeedsLayout when its frame gets set.

Subclassing UITextfield in Swift

I am currently initializing quite a few properties in my view controller, but it just feels very, very messy. I have been creating UITextField like:
lazy var passwordTextField: UITextField = {
let textField = UITextField()
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 30))
textField.leftView = paddingView
textField.leftViewMode = .always
textField.placeholder = "Password"
textField.isSecureTextEntry = true
textField.autocorrectionType = .no
textField.autocapitalizationType = UITextAutocapitalizationType.none
textField.attributedPlaceholder = NSAttributedString(string: "Password", attributes: [NSAttributedString.Key.foregroundColor: UIColor.lightGray])
textField.tintColor = UIColor.white
textField.borderStyle = .none
textField.layer.borderColor = UIColor.white.cgColor
textField.layer.borderWidth = 0.7
textField.delegate = self
textField.textColor = UIColor.white
return textField
}()
I have about 5 of these per UIViewController. I would like to create a UITextField class that is basically a factory that pumps out custom UITextFields. How might I accomplish this?
Subclassing any item is quite easy. Just do something like
class MyTextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
textFieldSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
textFieldSetup()
}
private func textFieldSetup() {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 30))
leftView = paddingView
leftViewMode = .always
...
...
//Add the common properties here that you want replicated for every instance
...
...
layer.borderColor = UIColor.white.cgColor
layer.borderWidth = 0.7
textColor = UIColor.white
}
}
Then, you can create an instance of MyTextField instead of UITextField
var passwordTextField: MyTextField!
You can subclass UITextField like,
class CustomTextField: UITextField {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.customInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.customInit()
}
func customInit(){
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 30))
self.leftView = paddingView
self.leftViewMode = .always
self.placeholder = "Password"
self.isSecureTextEntry = true
self.autocorrectionType = .no
self.autocapitalizationType = .none
self.attributedPlaceholder = NSAttributedString(string: "Password", attributes: [NSAttributedString.Key.foregroundColor: UIColor.lightGray])
self.tintColor = .white
self.borderStyle = .none
self.layer.borderColor = UIColor.white.cgColor
self.layer.borderWidth = 0.7
self.textColor = .white
}
}
To use the custom label or text field,
class ViewController: UIViewController {
#IBOutlet weak var myCustomTextField: CustomTextField!
}
You can create extension for textfield like,
extension UITextField {
func setLeftPaddingPoints(_ amount:CGFloat){
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.frame.size.height))
self.leftView = paddingView
self.leftViewMode = .always
}
func setRightPaddingPoints(_ amount:CGFloat) {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.frame.size.height))
self.rightView = paddingView
self.rightViewMode = .always
}
}

How to update CustomView width with different devices

I have a custom Button with 2 Labels and Image as shown in below class
import UIKit
#IBDesignable
class CustomButton : UIButton {
let secondLine : UILabel = UILabel()
override func layoutSubviews() {
super.layoutSubviews()
// self.layer.cornerRadius = 10
self.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.25).cgColor
self.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
self.layer.shadowOpacity = 1.0
self.layer.masksToBounds = false
}
#IBInspectable var rightLebelText : String?{
didSet {
updateView()
}
}
func updateView(){
if let mytext = rightLebelText {
let firstLine = UILabel(frame: CGRect(x: self.bounds.size.width - 210, y: 0, width: 200, height: 40))
firstLine.text = mytext
firstLine.textAlignment = .right
firstLine.font = UIFont.systemFont(ofSize: 20)
self.addSubview(firstLine)
var imageView : UIImageView
imageView = UIImageView(frame:CGRect(x: 5, y: 10, width: 20, height: 20))
imageView.image = UIImage(named:"arrow.png")
self.addSubview(imageView)
}
}
public func setSecondlabel(title : String){
secondLine.removeFromSuperview()
secondLine.frame = CGRect(x: 50, y: 0, width: 200, height: 40)
secondLine.text = title
secondLine.font = UIFont.boldSystemFont(ofSize: 20)
secondLine.removeFromSuperview()
self.addSubview(secondLine)
}
}
My issue is my view size is not updating on different devices when using
self.bounds.size.width
for the firstLine label as shown in below image its position should be on the custom button right edge
You need to override the layoutSubviews function have the frame of each element examine and update based on updated bounds of the custom view or assign proper layout constraints on each element while adding it.
If you are overriding the UIButton which has already a label and image property, you can use that one as well or create a custom class inherited from UIControl and create required three property as needed. I am adding an example of the custom class with image, title, and detail as shown in the problem.
class CustomButton : UIControl {
let imageView : UIImageView
let titleLabel : UILabel
let detailLabel : UILabel
fileprivate func setup() {
self.detailLabel.textAlignment = .right
self.detailLabel.font = UIFont.systemFont(ofSize: 20)
self.detailLabel.textColor = UIColor.black
self.titleLabel.font = UIFont.boldSystemFont(ofSize: 20)
self.titleLabel.textColor = UIColor.black
self.backgroundColor = UIColor.white
self.addSubview(self.imageView)
self.addSubview(self.titleLabel)
self.addSubview(self.detailLabel)
}
override init(frame: CGRect) {
self.imageView = UIImageView(frame: .zero)
self.titleLabel = UILabel(frame: .zero)
self.detailLabel = UILabel(frame: .zero)
super.init(frame: frame)
self.setup()
}
required init?(coder aDecoder: NSCoder) {
self.imageView = UIImageView(frame: .zero)
self.titleLabel = UILabel(frame: .zero)
self.detailLabel = UILabel(frame: .zero)
super.init(coder: aDecoder)
self.setup()
}
override func layoutSubviews() {
super.layoutSubviews()
self.imageView.frame = CGRect(x: 5.0, y: self.bounds.midY - 10.0, width: 20.0, height: 20.0)
//You can make this width dynamic if you want to calculate width of text using self.detailLabel.text
var width : CGFloat = 200.0
self.titleLabel.frame = CGRect(x: self.imageView.frame.maxX + 5.0, y: self.bounds.minY, width: 200.0, height: self.bounds.height)
//Give the remaining space to the second label
width = self.bounds.width - (self.titleLabel.frame.maxX + 15.0)
self.detailLabel.frame = CGRect(x: self.titleLabel.frame.maxX + 5.0, y: self.bounds.minY, width: width, height: self.bounds.height)
}
}

Adding Padding to UITextField [duplicate]

I want to leave a bit of space at the beginning of a UITextField, just like here:
Add lefthand margin to UITextField
But I don't know how to do that with Swift.
This is what I am using right now:
Swift 4.2, 5
class TextField: UITextField {
let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
override open func textRect(forBounds bounds: CGRect) -> CGRect {
return bounds.inset(by: padding)
}
override open func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return bounds.inset(by: padding)
}
override open func editingRect(forBounds bounds: CGRect) -> CGRect {
return bounds.inset(by: padding)
}
}
Swift 4
class TextField: UITextField {
let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
override open func textRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, padding)
}
override open func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, padding)
}
override open func editingRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, padding)
}
}
Swift 3:
class TextField: UITextField {
let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
override func textRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, padding)
}
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, padding)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, padding)
}
}
I never set a other padding but you can tweak. This class doesn't take care of the rightView and leftView on the textfield. If you want that to be handle correctly you can use something like (example in objc and I only needed the rightView:
- (CGRect)textRectForBounds:(CGRect)bounds {
CGRect paddedRect = UIEdgeInsetsInsetRect(bounds, self.insets);
if (self.rightViewMode == UITextFieldViewModeAlways || self.rightViewMode == UITextFieldViewModeUnlessEditing) {
return [self adjustRectWithWidthRightView:paddedRect];
}
return paddedRect;
}
- (CGRect)placeholderRectForBounds:(CGRect)bounds {
CGRect paddedRect = UIEdgeInsetsInsetRect(bounds, self.insets);
if (self.rightViewMode == UITextFieldViewModeAlways || self.rightViewMode == UITextFieldViewModeUnlessEditing) {
return [self adjustRectWithWidthRightView:paddedRect];
}
return paddedRect;
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
CGRect paddedRect = UIEdgeInsetsInsetRect(bounds, self.insets);
if (self.rightViewMode == UITextFieldViewModeAlways || self.rightViewMode == UITextFieldViewModeWhileEditing) {
return [self adjustRectWithWidthRightView:paddedRect];
}
return paddedRect;
}
- (CGRect)adjustRectWithWidthRightView:(CGRect)bounds {
CGRect paddedRect = bounds;
paddedRect.size.width -= CGRectGetWidth(self.rightView.frame);
return paddedRect;
}
This is a great case for an extension. By using an extension, there is no need to subclass UITextField and the new functionality will be made available to any UITextField in your app:
extension UITextField {
func setLeftPaddingPoints(_ amount:CGFloat){
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.frame.size.height))
self.leftView = paddingView
self.leftViewMode = .always
}
func setRightPaddingPoints(_ amount:CGFloat) {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.frame.size.height))
self.rightView = paddingView
self.rightViewMode = .always
}
}
When I need to set the padding of a text field anywhere in my application, I simply do the following:
textField.setLeftPaddingPoints(10)
textField.setRightPaddingPoints(10)
Using Swift extensions, the functionality is added to the UITextField directly without subclassing.
X, Y , Z are your desired values
textField.layer.sublayerTransform = CATransform3DMakeTranslation(x, y, z)
Such margin can be achieved by setting leftView / rightView to UITextField.
Updated For Swift 4
// Create a padding view for padding on left
textField.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 15, height: textField.frame.height))
textField.leftViewMode = .always
// Create a padding view for padding on right
textField.rightView = UIView(frame: CGRect(x: 0, y: 0, width: 15, height: textField.frame.height))
textField.rightViewMode = .always
I just added/placed an UIView to left and right side of the textfield. So now the typing will start after the view.
Thanks
Hope this helped...
Swift 4, Xcode 9
I like Pheepster's answer, but how about we do it all from the extension, without requiring VC code or any subclassing:
import UIKit
#IBDesignable
extension UITextField {
#IBInspectable var paddingLeftCustom: CGFloat {
get {
return leftView!.frame.size.width
}
set {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height))
leftView = paddingView
leftViewMode = .always
}
}
#IBInspectable var paddingRightCustom: CGFloat {
get {
return rightView!.frame.size.width
}
set {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height))
rightView = paddingView
rightViewMode = .always
}
}
}
Use my extension Swift 5 tested:
extension UITextField {
enum PaddingSpace {
case left(CGFloat)
case right(CGFloat)
case equalSpacing(CGFloat)
}
func addPadding(padding: PaddingSpace) {
self.leftViewMode = .always
self.layer.masksToBounds = true
switch padding {
case .left(let spacing):
let leftPaddingView = UIView(frame: CGRect(x: 0, y: 0, width: spacing, height: self.frame.height))
self.leftView = leftPaddingView
self.leftViewMode = .always
case .right(let spacing):
let rightPaddingView = UIView(frame: CGRect(x: 0, y: 0, width: spacing, height: self.frame.height))
self.rightView = rightPaddingView
self.rightViewMode = .always
case .equalSpacing(let spacing):
let equalPaddingView = UIView(frame: CGRect(x: 0, y: 0, width: spacing, height: self.frame.height))
// left
self.leftView = equalPaddingView
self.leftViewMode = .always
// right
self.rightView = equalPaddingView
self.rightViewMode = .always
}
}
}
How to use
// equal padding
yourTextField.addPadding(padding: .equalSpacing(10))
// padding right
yourTextField.addPadding(padding: .right(10))
// padding left
yourTextField.addPadding(padding: .left(10))
in Swift 4.2 and Xcode 10
Initially my text field is like this.
After adding padding in left side my text field is...
//Code for left padding
textFieldName.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: textFieldName.frame.height))
textFieldName.leftViewMode = .always
Like this we can create right side also.(textFieldName.rightViewMode = .always)
If you want SharedInstance type code(Write once use every ware) see the below code.
//This is my shared class
import UIKit
class SharedClass: NSObject {
static let sharedInstance = SharedClass()
//This is my padding function.
func textFieldLeftPadding(textFieldName: UITextField) {
// Create a padding view
textFieldName.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 3, height: textFieldName.frame.height))
textFieldName.leftViewMode = .always//For left side padding
textFieldName.rightViewMode = .always//For right side padding
}
private override init() {
}
}
Now call this function like this.
//This single line is enough
SharedClass.sharedInstance.textFieldLeftPadding(textFieldName:yourTF)
Simple swift 3 solution - add code to viewDidLoad:
let indentView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 20))
textField.leftView = indentView
textField.leftViewMode = .always
No need for ridiculously long code
Here is Haagenti's answer updated to Swift 4.2:
class PaddedTextField: UITextField {
func getPadding(plusExtraFor clearButtonMode: ViewMode) -> UIEdgeInsets {
var padding = UIEdgeInsets(top: 11, left: 16, bottom: 11, right: 16)
// Add additional padding on the right side when showing the clear button
if self.clearButtonMode == .always || self.clearButtonMode == clearButtonMode {
padding.right = 28
}
return padding
}
override open func textRect(forBounds bounds: CGRect) -> CGRect {
let padding = getPadding(plusExtraFor: .unlessEditing)
return bounds.inset(by: padding)
}
override open func placeholderRect(forBounds bounds: CGRect) -> CGRect {
let padding = getPadding(plusExtraFor: .unlessEditing)
return bounds.inset(by: padding)
}
override open func editingRect(forBounds bounds: CGRect) -> CGRect {
let padding = getPadding(plusExtraFor: .whileEditing)
return bounds.inset(by: padding)
}
}
Reference: Upgrading To Swift 4.2.
Edit: Account for clear button.
To create padding view for UITextField in Swift 5
func txtPaddingVw(txt:UITextField) {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 5, height: 5))
txt.leftViewMode = .always
txt.leftView = paddingView
}
This one line of code saved me:
For Xamarin.iOS:
textField.Layer.SublayerTransform = CATransform3D.MakeTranslation(5, 0, 0);
For Swift:
textField.layer.sublayerTransform = CATransform3DMakeTranslation(5, 0, 0);
Subclassing UITextField is the way to go. Open a playground and add the following code:
class MyTextField : UITextField {
var leftTextMargin : CGFloat = 0.0
override func textRectForBounds(bounds: CGRect) -> CGRect {
var newBounds = bounds
newBounds.origin.x += leftTextMargin
return newBounds
}
override func editingRectForBounds(bounds: CGRect) -> CGRect {
var newBounds = bounds
newBounds.origin.x += leftTextMargin
return newBounds
}
}
let tf = MyTextField(frame: CGRect(x: 0, y: 0, width: 100, height: 44))
tf.text = "HELLO"
tf.leftTextMargin = 25
tf.setNeedsLayout()
tf.layoutIfNeeded()
Easy way: to do this by extending UITextField
extension UITextField {
func setPadding(left: CGFloat? = nil, right: CGFloat? = nil){
if let left = left {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: left, height: self.frame.size.height))
self.leftView = paddingView
self.leftViewMode = .always
}
if let right = right {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: right, height: self.frame.size.height))
self.rightView = paddingView
self.rightViewMode = .always
}
}
}
Then you can set padding to any edge this way:
textField.setPadding(left: 5, right: 5)
In most cases you can regard this as a technicality but all the examples don't get the difference between frame and bounds right. When referencing the view's height in a subview, use bounds – otherwise you may run into trouble once some transform is applied to the parent.
See the updated code below (based on Pheepster's answer).
extension UITextField {
func setLeftPadding(_ amount: CGFloat = 10) {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.bounds.size.height))
self.leftView = paddingView
self.leftViewMode = .always
}
func setRightPadding(_ amount: CGFloat = 10) {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.bounds.size.height))
self.rightView = paddingView
self.rightViewMode = .always
}
}
Create UIView with required padding space and add it to textfield.leftView member and set textfield.leftViewMode member to UITextFieldViewMode.Always
// For example if you have textfield named title
#IBOutlet weak var title: UITextField!
// Create UIView
let paddingView : UIView = UIView(frame: CGRectMake(0, 0, 5, 20))
//Change your required space instaed of 5.
title.leftView = paddingView
title.leftViewMode = UITextFieldViewMode.Always
I prefer to use IBDesignable class and IBInspectable properties to allow me to set the padding via Xcode storyboards and keep it reusable. I've also updated the code to work in Swift 4.
import Foundation
import UIKit
#IBDesignable
class PaddableTextField: UITextField {
var padding = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
#IBInspectable var left: CGFloat = 0 {
didSet {
adjustPadding()
}
}
#IBInspectable var right: CGFloat = 0 {
didSet {
adjustPadding()
}
}
#IBInspectable var top: CGFloat = 0 {
didSet {
adjustPadding()
}
}
#IBInspectable var bottom: CGFloat = 0 {
didSet {
adjustPadding()
}
}
func adjustPadding() {
padding = UIEdgeInsets(top: top, left: left, bottom: bottom, right: right)
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
}
override func textRect(forBounds bounds: CGRect) -> CGRect {
return bounds.inset(by: UIEdgeInsets(top: top, left: left, bottom: bottom, right: right))
}
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return bounds.inset(by: UIEdgeInsets(top: top, left: left, bottom: bottom, right: right))
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return bounds.inset(by: UIEdgeInsets(top: top, left: left, bottom: bottom, right: right))
}
}
Put this code in your viewDidLoad():
textField.delegate = self
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: self.textField.frame.height))
textField.leftView = paddingView
textField.leftViewMode = UITextFieldViewMode.always
It works for me :)
ScareCrow's answer in Swift 3
let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5);
override func textRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, padding)
}
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, padding)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, padding)
}
In Swift 3.
You may use custom UITextField with indent that is set in its constructor. Don't need for extra declaration in a controller.
class CustomTextField : UITextField {
private let indentView = UIView(frame: CGRect(x: 0, y:0, width: 10, height: 10))
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.leftView = indentView
self.leftViewMode = .always
}
}
* Extending UITextField in Swift 5 *
import UIKit
#IBDesignable
extension UITextField {
#IBInspectable var paddingLeftCustom: CGFloat {
get {
return leftView!.frame.size.width
}
set {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height))
leftView = paddingView
leftViewMode = .always
}
}
#IBInspectable var paddingRightCustom: CGFloat {
get {
return rightView!.frame.size.width
}
set {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height))
rightView = paddingView
rightViewMode = .always
}
}
}
//MARK:- Use this class for different type of Roles
import UIKit
class HelperExtensionViewController: UIViewController {
}
//MARK:- Extension
extension UIImageView
{
func setImageCornerRadius()
{
self.layer.cornerRadius = self.frame.size.height/2
self.clipsToBounds = true
}
func setImageCornerRadiusInPoints(getValue:CGFloat)
{
self.layer.cornerRadius = getValue
self.clipsToBounds = true
}
}
extension UIButton
{
func setButtonCornerRadiusOnly()
{
self.layer.cornerRadius = self.frame.size.height/2
self.clipsToBounds = true
}
func setBtnCornerRadiusInPoints(getValue:CGFloat)
{
self.layer.cornerRadius = getValue
self.clipsToBounds = true
}
}
extension UITextField
{
func setTextFieldCornerRadiusWithBorder()
{
self.layer.cornerRadius = self.frame.size.height/2
self.layer.borderColor = UIColor.darkGray.cgColor
self.backgroundColor = UIColor.clear
self.layer.borderWidth = 0.5
self.clipsToBounds = true
}
func setLeftPaddingPoints(_ amount:CGFloat){
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.frame.size.height))
self.leftView = paddingView
self.leftViewMode = .always
}
func setRightPaddingPoints(_ amount:CGFloat) {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.frame.size.height))
self.rightView = paddingView
self.rightViewMode = .always
}
}
extension UIView
{
func setCornerRadius()
{
self.layer.cornerRadius = self.frame.size.height/2
self.clipsToBounds = true
}
// OUTPUT 1
func setViewCornerRadiusWithBorder()
{
self.layer.cornerRadius = self.frame.size.height/2
self.layer.borderColor = UIColor.init(red: 95.0/255.0, green: 229.0/255.0, blue: 206.0/255.0, alpha: 1.0).cgColor
self.backgroundColor = UIColor.clear
self.layer.borderWidth = 1.0
self.clipsToBounds = true
}
func layoutSubviews(myView:UIView)
{
let shadowPath = UIBezierPath(rect: myView.bounds)
myView.layer.masksToBounds = false
myView.layer.shadowColor = UIColor.lightGray.cgColor
myView.layer.shadowOffset = CGSize(width: -1.0, height: 2.0)
myView.layer.shadowOpacity = 0.5
myView.layer.shadowPath = shadowPath.cgPath
}
func layoutSubviews2(myView:UIView)
{
let shadowPath = UIBezierPath(rect: myView.bounds)
myView.clipsToBounds = true
myView.layer.masksToBounds = false
myView.layer.shadowColor = UIColor.black.cgColor
myView.layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
myView.layer.shadowOpacity = 0.2
myView.layer.shadowPath = shadowPath.cgPath
}
func setViewCornerRadiusInPoints(getValue:CGFloat)
{
self.layer.cornerRadius = getValue
self.clipsToBounds = true
}
func dropShadow(scale: Bool = true) {
layer.masksToBounds = false
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.5
layer.shadowOffset = CGSize(width: -1, height: 1)
layer.shadowRadius = 1
layer.shadowPath = UIBezierPath(rect: bounds).cgPath
layer.shouldRasterize = true
layer.rasterizationScale = scale ? UIScreen.main.scale : 1
}
// OUTPUT 2
func dropShadow(color: UIColor, opacity: Float = 0.5, offSet: CGSize, radius: CGFloat = 1, scale: Bool = true) {
layer.masksToBounds = false
layer.shadowColor = color.cgColor
layer.shadowOpacity = opacity
layer.shadowOffset = offSet
layer.shadowRadius = radius
layer.shadowPath = UIBezierPath(rect: self.bounds).cgPath
layer.shouldRasterize = true
layer.rasterizationScale = scale ? UIScreen.main.scale : 1
}
func setGradientBackground(myview:UIView) {
let colorTop = UIColor(red: 100.0/255.0, green: 227.0/255.0, blue: 237.0/255.0, alpha: 1.0).cgColor
let colorBottom = UIColor(red: 141.0/255.0, green: 109.0/255.0, blue: 164.0/255.0, alpha: 1.0).cgColor
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [colorTop, colorBottom]
gradientLayer.locations = [1.0, 1.0]
gradientLayer.frame = myview.bounds
myview.layer.insertSublayer(gradientLayer, at:0)
}
}
To Extend original answer for leftView and Swift5+
class TextField: UITextField {
let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
override open func textRect(forBounds bounds: CGRect) -> CGRect {
let paddedRect = bounds.inset(by: self.padding)
if (self.leftViewMode == .always || self.leftViewMode == .unlessEditing) {
return self.adjustRectOriginForLeftView(bounds: paddedRect)
}
return paddedRect
}
override open func placeholderRect(forBounds bounds: CGRect) -> CGRect {
let paddedRect = bounds.inset(by: self.padding)
if (self.leftViewMode == .always || self.leftViewMode == .unlessEditing) {
return self.adjustRectOriginForLeftView(bounds: paddedRect)
}
return paddedRect;
}
override open func editingRect(forBounds bounds: CGRect) -> CGRect {
let paddedRect = bounds.inset(by: self.padding);
if (self.leftViewMode == .always || self.leftViewMode == .unlessEditing) {
return self.adjustRectOriginForLeftView(bounds: paddedRect)
}
return paddedRect;
}
func adjustRectOriginForLeftView(bounds : CGRect) -> CGRect{
var paddedRect = bounds;
paddedRect.origin.x += self.leftView!.frame.width
return paddedRect
}
}
Create space at the beginning of a UITextField.
in Swift 5+ and Xcode 12.
textFieldName.setLeftPaddingPoints(CGFloat(10))
textFieldName.setRightPaddingPoints(CGFloat(10)

Add subviews on Customize UIView works not as expect

I subclass a class of UIView called:AURTabView. Then I drag 3 views(white background) to storyboard to auto layout them with 1/3 screen width of each. Then i add a UIButton on the init method, it works well so far as below:
Then i want to add another two UIViews on to them. The weird thing is the first and third AUTRabView works as expect, but the middle one doesn't.
This is really weird. I checked UIView hierarchy like below:
Any point?
Here is the code:
class AURTabView: UIView {
let tabButton = UIButton()
let smallCircle = UIView()
let largeCircle = UIView()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addSubview(tabButton)
self.addSubview(smallCircle)
self.addSubview(largeCircle)
}
override func layoutSubviews() {
super.layoutSubviews()
let height = self.frame.height
tabButton.frame = CGRect(x: (self.frame.width-height)/2, y: 0, width: height, height: height)
tabButton.backgroundColor = UIColor.greenColor()
smallCircle.frame = CGRect(x: CGRectGetMidX(self.frame)-2.5, y: height-10-8, width: 5, height: 5)
smallCircle.backgroundColor = UIColor.redColor()
largeCircle.frame = CGRect(x: CGRectGetMidX(self.frame)-5, y: height-8, width: 10, height: 10)
largeCircle.backgroundColor = UIColor.redColor()
print(smallCircle)
print(largeCircle)
}
override func drawRect(rect: CGRect) {
tabButton.layer.cornerRadius = tabButton.frame.width/2
}
}
Use this
import UIKit
class AURTabView: UIView {
let tabButton = UIButton()
let smallCircle = UIView()
let largeCircle = UIView()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addSubview(tabButton)
self.addSubview(smallCircle)
self.addSubview(largeCircle)
}
override func layoutSubviews() {
super.layoutSubviews()
let height = self.frame.height
tabButton.frame = CGRect(x: (self.frame.width-height)/2, y: 0, width: height, height: height)
tabButton.backgroundColor = UIColor.greenColor()
smallCircle.frame = CGRect(x: self.frame.width/2 - 2.5, y: height-10-8, width: 5, height: 5)
smallCircle.backgroundColor = UIColor.blackColor()
largeCircle.frame = CGRect(x: self.frame.width/2 - 5, y: height-8, width: 10, height: 10)
largeCircle.backgroundColor = UIColor.redColor()
print(smallCircle)
print(largeCircle)
}
override func drawRect(rect: CGRect) {
tabButton.layer.cornerRadius = tabButton.frame.width/2
}
}

Resources