I wanted to use a custom background for my UITextFields
. This works fine except for the fact that I have to use UITextBorderStyleNone
to make it look pretty. This forces the text to stick to the left without any padding.
Can I set a padding manually so that it looks similar to UITextBorderStyleRoundedRect
except for using my custom background image?
A good approach to add padding to UITextField is to subclass and add an edgeInsets property. You then set the edgeInsets and the UITextField will be drawn accordingly. This will also function correctly with a custom leftView or rightView set. This should be accepted answer.
I found a neat little hack to set the left padding for this exact situation.
Basically, you set the leftView property of the UITextField
to be an empty view of the size of the padding you want:
UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
textField.leftView = paddingView;
textField.leftViewMode = UITextFieldViewModeAlways;
Worked like a charm for me!
In Swift 3/ Swift 4, it can be done by doing that
let paddingView: UIView = UIView(frame: CGRect(x: 0, y: 0, width: 5, height: 20))
textField.leftView = paddingView
textField.leftViewMode = .always
I created this category implementation and added it to the top of the .m
file.
@implementation UITextField (custom)
- (CGRect)textRectForBounds:(CGRect)bounds {
return CGRectMake(bounds.origin.x + 10, bounds.origin.y + 8,
bounds.size.width - 20, bounds.size.height - 16);
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
return [self textRectForBounds:bounds];
}
@end
Based off the link Piotr Blasiak provided. It seemed simpler then creating a whole new subclass, and also simpler then adding the additional UIView
. Still, it seems like something is missing to not be able to control the padding inside a text field.
Swift 4 solution:
class CustomTextField: UITextField {
struct Constants {
static let sidePadding: CGFloat = 10
static let topPadding: CGFloat = 8
}
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(
x: bounds.origin.x + Constants.sidePadding,
y: bounds.origin.y + Constants.topPadding,
width: bounds.size.width - Constants.sidePadding * 2,
height: bounds.size.height - Constants.topPadding * 2
)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return self.textRect(forBounds: bounds)
}
}
A Swift 3 version for Xcode >6, where you can edit the inset value in Interface Builder / Storyboard.
import UIKit
@IBDesignable
class FormTextField: UITextField {
@IBInspectable var inset: CGFloat = 0
override func textRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: inset, dy: inset)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return textRect(forBounds: bounds)
}
}
Edit: Still works in iOS 11.3.1
In iOS 6 myTextField.leftView = paddingView;
is causing issue
This solves the problem
myTextField.layer.sublayerTransform = CATransform3DMakeTranslation(5, 0, 0)
For right aligned text field use CATransform3DMakeTranslation(-5, 0, 0)
as mention by latenitecoder in comments
A good approach to add padding to UITextField is to subclass and add an edgeInsets property. You then set the edgeInsets and the UITextField will be drawn accordingly. This will also function correctly with a custom leftView or rightView set.
OSTextField.h
#import <UIKit/UIKit.h>
@interface OSTextField : UITextField
@property (nonatomic, assign) UIEdgeInsets edgeInsets;
@end
OSTextField.m
#import "OSTextField.h"
@implementation OSTextField
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
self.edgeInsets = UIEdgeInsetsZero;
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if(self){
self.edgeInsets = UIEdgeInsetsZero;
}
return self;
}
- (CGRect)textRectForBounds:(CGRect)bounds {
return [super textRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
return [super editingRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}
@end
Just subclass UITextField like this:
@implementation DFTextField
- (CGRect)textRectForBounds:(CGRect)bounds
{
return CGRectInset(bounds, 10.0f, 0);
}
- (CGRect)editingRectForBounds:(CGRect)bounds
{
return [self textRectForBounds:bounds];
}
@end
This adds horizontal padding of 10 points either side.
PaddingTextField.swift
import UIKit
class PaddingTextField: UITextField {
@IBInspectable var paddingLeft: CGFloat = 0
@IBInspectable var paddingRight: CGFloat = 0
override func textRectForBounds(bounds: CGRect) -> CGRect {
return CGRectMake(bounds.origin.x + paddingLeft, bounds.origin.y,
bounds.size.width - paddingLeft - paddingRight, bounds.size.height);
}
override func editingRectForBounds(bounds: CGRect) -> CGRect {
return textRectForBounds(bounds)
}}
Set your textfield class is PaddingTextField and custom your padding as you want
Enjoy it
Objective C Code
MyTextField.h
#import <UIKit/UIKit.h>
@interface MyTextField : UITextField
@property (nonatomic) IBInspectable CGFloat padding;
@end
MyTextField.m
#import "MyTextField.h"
IB_DESIGNABLE
@implementation MyTextField
@synthesize padding;
-(CGRect)textRectForBounds:(CGRect)bounds{
return CGRectInset(bounds, padding, padding);
}
-(CGRect)editingRectForBounds:(CGRect)bounds{
return [self textRectForBounds:bounds];
}
@end
Based on Evil Trout's answer you might wanna create a category to make it easier to use across multiple applications.
Header file:
@interface UITextField (PaddingText)
-(void) setLeftPadding:(int) paddingValue;
-(void) setRightPadding:(int) paddingValue;
@end
Implementation file:
#import "UITextField+PaddingText.h"
@implementation UITextField (PaddingText)
-(void) setLeftPadding:(int) paddingValue
{
UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, paddingValue, self.frame.size.height)];
self.leftView = paddingView;
self.leftViewMode = UITextFieldViewModeAlways;
}
-(void) setRightPadding:(int) paddingValue
{
UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, paddingValue, self.frame.size.height)];
self.rightView = paddingView;
self.rightViewMode = UITextFieldViewModeAlways;
}
@end
Usage Example
#import "UITextField+PaddingText.h"
[self.YourTextField setLeftPadding:20.0f];
Hope it helps you out guys
Cheers
Swift version:
extension UITextField {
@IBInspectable var padding_left: CGFloat {
get {
LF.log("WARNING no getter for UITextField.padding_left")
return 0
}
set (f) {
layer.sublayerTransform = CATransform3DMakeTranslation(f, 0, 0)
}
}
}
So that you can assign value in IB
You can't set padding. Instead have a UIView
which has your background image and the UITextField
inside of it. Set the UITextField
width as UIViewWidth-(paddingSize x 2)
and the height similarly and then set it at point paddingSize,paddingSize
.
Just subclass UITextField like this (Swift version):
import UIKit
class CustomTextField: UITextField {
override func textRectForBounds(bounds: CGRect) -> CGRect {
return CGRectInset(bounds, 25.0, 0)
}
override func editingRectForBounds(bounds: CGRect) -> CGRect {
return self.textRectForBounds(bounds)
}
}
This adds horizontal padding of 25.0 points either side.
I was based off Nate's solution, but then i found it that this causes problems when you use the leftView/rightView properties, so its better tune the super's implementation, because it will take the left/right view's into account.
- (CGRect)textRectForBounds:(CGRect)bounds {
CGRect ret = [super textRectForBounds:bounds];
ret.origin.x = ret.origin.x + 5;
ret.size.width = ret.size.width - 10;
return ret;
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
return [self textRectForBounds:bounds];
}
Updated version for Swift 3:
@IBDesignable
class FormTextField: UITextField {
@IBInspectable var paddingLeft: CGFloat = 0
@IBInspectable var paddingRight: CGFloat = 0
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + paddingLeft, y: bounds.origin.y, width: bounds.size.width - paddingLeft - paddingRight, height: bounds.size.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return textRect(forBounds: bounds)
}
}
Based on @Evil Trout's most voted answer I created a custom method in my ViewController class, like shown bellow:
- (void) modifyTextField:(UITextField *)textField
{
UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
textField.leftView = paddingView;
textField.leftViewMode = UITextFieldViewModeAlways;
textField.rightView = paddingView;
textField.rightViewMode = UITextFieldViewModeAlways;
[textField setBackgroundColor:[UIColor whiteColor]];
[textField setTextColor:[UIColor blackColor]];
}
Now I can call that method inside (viewDidLoad method) and send any of my TextFields to that method and add padding for both right and left, and give text and background colors by writing just one line of code, as follows:
[self modifyTextField:self.firstNameTxtFld];
This Worked perfectly on iOS 7! I know that adding too much Views might make this a bit heavier class to be loaded. But when concerned about the difficulty in other solutions, I found myself more biased to this method and more flexible with using this way. ;)
Thanks for the Hack "Evil Trout"! (bow)
I thought I should update this answer's code snippet with Swift:
Since Swift allow us to write extensions for the existing classes, let's write it in that way.
extension UITextField {
func addPaddingToTextField() {
let paddingView: UIView = UIView.init(frame: CGRectMake(0, 0, 8, 20))
self.leftView = paddingView;
self.leftViewMode = .Always;
self.rightView = paddingView;
self.rightViewMode = .Always;
self.backgroundColor = UIColor.whiteColor()
self.textColor = UIColor.blackColor()
}
}
Usage:
self.firstNameTxtFld.addPaddingToTextField()
Hope this would be helpful to somebody else out there!
Cheers!
Here's how to achieve this in SWIFT
@IBOutlet weak var yourTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let paddingView = UIView(frame: CGRectMake(0, 0, 10, self.yourTextField.frame.height))
yourTextField.leftView = paddingView
yourTextField.leftViewMode = UITextFieldViewMode.Always
}
}
Resource
Swift 2.0 Version:
let paddingView: UIView = UIView(frame: CGRectMake(0, 0, 5, 20))
textField.leftView = paddingView
textField.leftViewMode = UITextFieldViewMode.Always;
If anyone is looking for Swift 4.0
version then below extension
is work. It has both Left
and Right
padding for UITextField
. Actually it is IBInspectable
for storyboard configuration. You can set the value directly from the Interface Builder / Storyboard. This is tested code in Swift 4.0 version and Xcode 9.0
Keep in mind that if you want to enable Clear Button
on the same UITextField
then your have to keep Right Padding blank.
import UIKit
extension UITextField {
@IBInspectable var paddingLeft: 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 paddingRight: 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
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With