95

The leftView and rightView views of an UITextField on iOS7 are really close to the textfield border.

How may I add some (horizontal) padding to those items?

I tried modifying the frame, but did not work

uint padding = 10;//padding for iOS7
UIImageView * iconImageView = [[UIImageView alloc] initWithImage:iconImage];    
iconImageView.frame = CGRectMake(0 + padding, 0, 16, 16);
textField.leftView = iconImageView;

Please, note that I'm not interested in adding padding to the textfield's text, like this Set padding for UITextField with UITextBorderStyleNone

Pramod More
  • 1,220
  • 2
  • 22
  • 51
subzero
  • 3,420
  • 5
  • 31
  • 40
  • possible duplicate of [Text inset for UITextField?](http://stackoverflow.com/questions/2694411/text-inset-for-uitextfield) – Zorayr Dec 22 '14 at 22:39
  • 1
    No, this is asking about indenting the image displayed as a leftView in a text field. Not indenting the text itself. Try his code and you'll see that setting leftView to an image places that image up against the left edge of the text field, with no padding. It looks ugly. – stone Jan 27 '15 at 05:14

28 Answers28

167

A much simpler solution, which takes advantage of contentMode:

    arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"down_arrow"]];
    arrow.frame = CGRectMake(0.0, 0.0, arrow.image.size.width+10.0, arrow.image.size.height);
    arrow.contentMode = UIViewContentModeCenter;

    textField.rightView = arrow;
    textField.rightViewMode = UITextFieldViewModeAlways;

In Swift 3,

    let arrow = UIImageView(image: UIImage(named: "arrowDrop"))
    if let size = arrow.image?.size {
        arrow.frame = CGRect(x: 0.0, y: 0.0, width: size.width + 10.0, height: size.height)
    }
    arrow.contentMode = UIViewContentMode.center
    self.textField.rightView = arrow
    self.textField.rightViewMode = UITextFieldViewMode.always
idrougge
  • 633
  • 5
  • 12
TTillage
  • 1,886
  • 2
  • 12
  • 10
  • 1
    You can use ScaleAspectFit too instead of centre ... if image's size is not matching with the exact frame. – Mihir Mehta Sep 27 '15 at 16:46
  • I used your example for UIButton (instead of UIImageView) while its type is InfoLight. – OhadM Jan 14 '16 at 14:55
  • I found that ".right" instead of ".center" makes it look more like a built-in Search bar such as the one in the Contacts app. Great solution on this, thanks for posting it. – James Toomey Dec 28 '17 at 18:20
  • Or if you need to be precise in design recreation, put the image to the .left and then increase the width to achieve exact padding – jovanjovanovic Aug 22 '18 at 12:12
  • This doesn't work great with vector icons (pdfs) because they seem to be scaling to fill the available space. – Andrew Kirna Jul 09 '19 at 17:44
  • 8
    This does not seem to work anymore with iOS 13 and Xcode 11 Beta 7. Works fine on iOS 11/12 though. – PatrickDotStar Sep 02 '19 at 15:33
101

Was just working on this myself and used this solution:

- (CGRect) rightViewRectForBounds:(CGRect)bounds {

    CGRect textRect = [super rightViewRectForBounds:bounds];
    textRect.origin.x -= 10;
    return textRect;
}

This will move the image over from the right by 10 instead of having the image squeezed up against the edge in iOS 7.

Additionally, this was in a subclass of UITextField, which can be created by:

  1. Create a new file that's a subclass of UITextField instead of the default NSObject
  2. Add a new method named - (id)initWithCoder:(NSCoder*)coder to set the image

    - (id)initWithCoder:(NSCoder*)coder {
        self = [super initWithCoder:coder];
    
        if (self) {
    
            self.clipsToBounds = YES;
            [self setRightViewMode:UITextFieldViewModeUnlessEditing];
    
            self.leftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"textfield_edit_icon.png"]];
        }
    
        return self;
    }
    
  3. You may have to import #import <QuartzCore/QuartzCore.h>

  4. Add the rightViewRectForBounds method above

  5. In Interface Builder, click on the TextField you would like to subclass and change the class attribute to the name of this new subclass

AngeloS
  • 5,536
  • 7
  • 40
  • 58
51

Easiest way is add a UIView to leftView/righView and add an ImageView to UIView , adjust the origin of ImageView inside UIView anywhere you like , this worked for me like a charm. It needs only few lines of code

UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 5, 26, 26)];
imgView.image = [UIImage imageNamed:@"img.png"];

UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
[paddingView addSubview:imgView];
[txtField setLeftViewMode:UITextFieldViewModeAlways];
[txtField setLeftView:paddingView];
vishal dharankar
  • 7,536
  • 7
  • 57
  • 93
15

This works great for Swift:

let imageView = UIImageView(image: UIImage(named: "image.png"))
imageView.contentMode = UIViewContentMode.Center
imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 20.0, imageView.image!.size.height)
textField.rightViewMode = UITextFieldViewMode.Always
textField.rightView = imageView
richsage
  • 26,912
  • 8
  • 58
  • 65
Andrew
  • 3,733
  • 1
  • 35
  • 36
  • cannot convert value of type 'string' to expected argument type 'UIImage?" –  Nov 28 '15 at 12:26
9

This works for me

UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 20)];
self.passwordTF.leftView = paddingView;
self.passwordTF.leftViewMode = UITextFieldViewModeAlways;

May it helps you.

Ashu
  • 3,373
  • 38
  • 34
6

I like this solution because it solves the problem with a single line of code

myTextField.layer.sublayerTransform = CATransform3DMakeTranslation(10.0f, 0.0f, 0.0f);

Note: .. or 2 if you consider including QuartzCore a line :)

Jordi Corominas
  • 1,244
  • 10
  • 15
  • 1
    This also moves the border – Softlion Apr 07 '15 at 13:49
  • 1
    but doesn't solve the problem with the right padding only the left padding problem – Carmen Apr 17 '15 at 13:32
  • 1
    I had a better result using rightView.layer.sublayerTransform = CATransform3DMakeTranslation(-10.0f, 0.0f, 0.0f), but +1 for the method – Thibaud David May 20 '15 at 07:33
  • Keep in mind this will also shift the text field's "clear" button to the right, which can push it past the edge of the text field. If you don't need the clear button, this is a great approach, otherwise maybe not. – Tom Harrington Apr 11 '17 at 17:50
6

Swift 5

class CustomTextField: UITextField {
    func invalidate() {
        let errorImage =  UIImageView(image: UIImage(named: "errorImage"))
        errorImage.frame = CGRect(x: 8, y: 8, width: 16, height: 16)
        rightView = UIView(frame: CGRect(x: 0, y: 0, width: 32, height: 32))
        rightView?.addSubview(errorImage)
        rightViewMode = .always
    }
}

You'll want to:

  • Subclass UITextField
  • Write an invalidate method inside the subclassed text field
  • In the invalidate method, create a UIView larger than your image
  • Place your image inside the view
  • Assign the view to UITextField.rightView
swiftyboi
  • 2,965
  • 4
  • 25
  • 52
5

Instead of manipluating imageView or image we can override a method provided by apple for rightView.

class CustomTextField : UITextField { 

override func rightViewRect(forBounds bounds: CGRect) -> CGRect {
    let offset = 5
    let width  = 20
    let height = width
    let x = Int(bounds.width) - width - offset
    let y = offset
    let rightViewBounds = CGRect(x: x, y: y, width: width, height: height)
    return rightViewBounds
}}

and same way we can override below func for left view.

override func leftViewRect(forBounds bounds: CGRect) -> CGRect {
    /*return as per requirement*/

}
Pranav Gupta
  • 741
  • 9
  • 10
4

The best way to do this is simply make a class using subclass of UITextField and in .m file

  #import "CustomTextField.h"
  #import <QuartzCore/QuartzCore.h>
  @implementation CustomTextField


- (id)initWithCoder:(NSCoder*)coder 
 {
self = [super initWithCoder:coder];

if (self) {

    //self.clipsToBounds = YES;
    //[self setRightViewMode:UITextFieldViewModeUnlessEditing];

    self.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,15,46)];
    self.leftViewMode=UITextFieldViewModeAlways;
      }

return self;

}

by doing this go to your storyboard or xib and click on identity inspector and replace UITextfield with your own "CustomTextField" in class option.

Note: If you simply give padding with auto layout for textfield then your application will not run and show only blank screen.

Anuj Kumar Rai
  • 666
  • 1
  • 6
  • 17
4

Since iOS 13 and Xcode 11 this is the only solution that works for us.

// Init of custom UITextField
override init(frame: CGRect) {
    super.init(frame: frame)

    if let size = myButton.imageView?.image?.size {
        myButton.frame = CGRect(x:0, y: 0, width: size.width, height: size.height)

        let padding: CGFloat = 5
        let container = UIView(frame: CGRect(x:0, y: 0, width: size.width + padding, height: size.height))
        container.addSubview(myButton)

        myButton.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            myButton.topAnchor.constraint(equalTo: container.topAnchor),
            myButton.leftAnchor.constraint(equalTo: container.leftAnchor),
            myButton.bottomAnchor.constraint(equalTo: container.bottomAnchor),
            myButton.rightAnchor.constraint(equalTo: container.rightAnchor, constant: -padding),
        ])

        textField.rightViewMode = .always
        textField.rightView = container
    }
}
PatrickDotStar
  • 1,654
  • 1
  • 19
  • 20
4

Maybe you might set up an empty view and embed your view as a subview:

let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 50.0, height: 50.0))
imageView.contentMode = .center
imageView.image = UIImage(named: "ic_dropdown")
let emptyView = UIView(frame: CGRect(x: 0, y: 0, width: 50.0, height: 50.0))
emptyView.backgroundColor = .clear
emptyView.addSubview(imageView)
self.documentTypeTextLabel.rightView = emptyView
self.documentTypeTextLabel.rightViewMode = .always

enter image description here

Happy coding

Alfredo Luco G
  • 876
  • 7
  • 18
3

I found this somewhere...

UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
paddingView.backgroundColor = [UIColor clearColor];
itemDescription.leftView = paddingView;
itemDescription.leftViewMode = UITextFieldViewModeAlways;

[self addSubview:itemDescription];
RegularExpression
  • 3,531
  • 2
  • 25
  • 36
1

Create a custom UITextField class and use that class instead of UITextField. Override - (CGRect) textRectForBounds:(CGRect)bounds to set the rect that you need

Example

- (CGRect)textRectForBounds:(CGRect)bounds{
     CGRect textRect = [super textRectForBounds:bounds];
     textRect.origin.x += 10;
     textRect.size.width -= 10;
     return textRect;
}
Shaik Riyaz
  • 11,204
  • 7
  • 53
  • 70
Kedar
  • 1,298
  • 10
  • 20
1

Here is one solution:

 UIView *paddingTxtfieldView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 42)]; // what ever you want 
 txtfield.leftView = paddingTxtfieldView;
 txtfield.leftViewMode = UITextFieldViewModeAlways;
Zorayr
  • 23,770
  • 8
  • 136
  • 129
Dev Patel
  • 290
  • 1
  • 9
  • The question is regarding add padding to the left/right view, you are replacing the left and right view with your solution! – Tejas K Jul 21 '21 at 20:28
1

I created a custom method in my ViewController class, like shown bellow:

- (void) modifyTextField:(UITextField *)textField
{
    // Prepare the imageView with the required image
    uint padding = 10;//padding for iOS7
    UIImageView * iconImageView = [[UIImageView alloc] initWithImage:iconImage];    
    iconImageView.frame = CGRectMake(0 + padding, 0, 16, 16);

    // Set the imageView to the left of the given text field.
    textField.leftView = iconImageView;
    textField.leftViewMode = UITextFieldViewModeAlways;
}

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! Hope this still works on iOS 8 and 9 too!

I know that adding too much Views might make this a bit heavier object 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. ;)

Hope this answer might be helpful or useful to figure out another solution to someone else.

Cheers!

Randika Vishman
  • 7,983
  • 3
  • 57
  • 80
1

Below example is for adding horizontal padding to a left view that happens to be an icon - you can use the similar approach for adding padding to any UIView that you would like to use as the textfield's left view.

Inside UITextField subclass:

static CGFloat const kLeftViewHorizontalPadding = 10.0f;

@implementation TextFieldWithLeftIcon
{
  UIImage *_image;
  UIImageView *_imageView;
}

- (instancetype)initWithFrame:(CGRect)frame image:(UIImage *)image
{
  self = [super initWithFrame:frame];
  if (self) {
    if (image) {
      _image = image;
      _imageView = [[UIImageView alloc] initWithImage:image];
      _imageView.contentMode = UIViewContentModeCenter;
      self.leftViewMode = UITextFieldViewModeAlways;
      self.leftView = _imageView;
    }
  }
  return self;
}

#pragma mark - Layout 

- (CGRect)leftViewRectForBounds:(CGRect)bounds
{
  CGFloat widthWithPadding = _image.size.width + kLeftViewHorizontalPadding * 2.0f;
  return CGRectMake(0, 0, widthWithPadding, CGRectGetHeight(bounds));
}

Although we are a subclassing UITextField here, I believe this is the cleanest approach.

Zorayr
  • 23,770
  • 8
  • 136
  • 129
1
- (CGRect)rightViewRectForBounds:(CGRect)bounds
{
    return CGRectMake(bounds.size.width - 40, 0, 40, bounds.size.height);
}
Carmen
  • 6,177
  • 1
  • 35
  • 40
  • If the `UITextField` is embedded in a `UISearchBar`, how do you tell the `UISearchBar` to use your `UITextField` subclass? – crishoj May 18 '15 at 10:39
1

thank you guys for your answers, to my surprise none of them really fitted the right view image to my textfield while still providing the needed padding. then i thought of using the AspectFill mode and miracles happened. for future seekers, here's what i used:

UIImageView *emailRightView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 35, 35)];
emailRightView.contentMode = UIViewContentModeScaleAspectFill;
emailRightView.image = [UIImage imageNamed:@"icon_email.png"];
emailTextfield.rightViewMode = UITextFieldViewModeAlways;
emailTextfield.rightView = emailRightView;

the 35 in the frame of my imageview represents the height of my emailTextfield, feel free to adjust it to your needs.

carlos16196
  • 706
  • 1
  • 7
  • 10
1

If you are using a UIImageView as leftView then you have to use this code :

Caution : Don't use inside viewWillAppear or viewDidAppear

-(UIView*)paddingViewWithImage:(UIImageView*)imageView andPadding:(float)padding
{
    float height = CGRectGetHeight(imageView.frame);
    float width =  CGRectGetWidth(imageView.frame) + padding;

    UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)];

    [paddingView addSubview:imageView];

    return paddingView;
}
Zeeshan
  • 4,194
  • 28
  • 32
1

This works for me just like I looking for:

func addImageViewInsideMyTextField() {
    let someView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 24))
    let imageView = UIImageView(image: UIImage(named: "accountImage"))
    imageView.frame = CGRect(x: 16, y: 0, width: 24, height: 24)
    imageView.contentMode = .scaleAspectFit
    someView.addSubview(imageView)

    self.myTextField.leftView = someView
    self.myTextField.leftViewMode = .always
}
1

Set Rightview of UITextField using swift 4.2

TxtPass.rightViewMode = UITextField.ViewMode.always
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 18, height: 18))
imageView.contentMode = UIView.ContentMode.scaleAspectFit
let image = UIImage(named: "hidepass")
imageView.image = image
let rightView = UIView(frame: CGRect(x: 0, y: 0, width: 28, height: 18))
rightView.addSubview(imageView)
rightView.contentMode = UIView.ContentMode.left
TxtPass.rightView = rightView
Anurag Sharma
  • 4,276
  • 2
  • 28
  • 44
NSurajit
  • 413
  • 4
  • 10
0

One trick: Add a UIView containing UIImageView to UITextField as rightView. This UIView must be larger in size, now place the UIImageView to left of it. So there will be a padding of space from right.

// Add a UIImageView to UIView and now this UIView to UITextField - txtFieldDate
UIView *viewRightIntxtFieldDate = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 30)]; 
// (Height of UITextField is 30px so height of viewRightIntxtFieldDate = 30px)
UIImageView *imgViewCalendar = [[UIImageView alloc] initWithFrame:CGRectMake(0, 10, 10, 10)];
[imgViewCalendar setImage:[UIImage imageNamed:@"calendar_icon.png"]];
[viewRightIntxtFieldDate addSubview:imgViewCalendar];
txtFieldDate.rightViewMode = UITextFieldViewModeAlways;
txtFieldDate.rightView = viewRightIntxtFieldDate;
iain
  • 5,660
  • 1
  • 30
  • 51
Suraj Mirajkar
  • 1,369
  • 10
  • 23
0

I have had this problem myself, and by far the easiest solution is to modify your image to simply add padding to each side of the image!

I just altered my png image to add 10 pixels transparent padding, and it works well, with no coding at all!

R2D2
  • 2,620
  • 4
  • 24
  • 46
0

Easiest way is just change the Textfield as RoundRect instead of Custom and see the magic. :)

Shilpa
  • 340
  • 1
  • 4
  • 14
0

for Swift2 , I use

...
        self.mSearchTextField.leftViewMode = UITextFieldViewMode.Always
        let searchImg = UIImageView(image: UIImage(named: "search.png"))
        let size = self.mSearchTextField.frame.height
        searchImg.frame = CGRectMake(0, 0, size,size)
        searchImg.contentMode = UIViewContentMode.ScaleAspectFit
        self.mSearchTextField.leftView = searchImg
...
Thomas G
  • 9,886
  • 7
  • 28
  • 41
Haiyuan
  • 103
  • 2
  • 5
0
...
textField.rightView = UIImageView(image: ...)
textField.rightView?.contentMode = .top
textField.rightView?.bounds.size.height += 10
textField.rightViewMode = .always
...
0

I realize this an old post and this answer is a bit specific to my use case, but I posted it in case others are seeking a similar solution. I want to move a UITextField's leftView or rightView but I am not putting images in them and do not want any hard coded constants.

My UI calls for hiding the text field's clear button and displaying a UIActivityIndicatorView where the clear button was located.

I add a spinner to the rightView, but out of the box (on iOS 13) it is shifted 20 pixels to the right of the clearButton. I don't like to use magic numbers since the position of the clearButton and rightView are subject to change at any time by Apple. The UI design intent is "spinner where the clear button is" so my solution was to subclass UITextField and override rightViewRect(forBounds).

override func rightViewRect(forBounds bounds: CGRect) -> CGRect {

    // Use clearButton's rectangle
    return self.clearButtonRect(forBounds: bounds)
}

Below is a working example (sans Storyboard):

//------------------------------------------------------------------------------
class myCustomTextField: UITextField {

    override func rightViewRect(forBounds bounds: CGRect) -> CGRect {

        // Use clearButton rectangle
        return self.clearButtonRect(forBounds: bounds)
    }
}

//------------------------------------------------------------------------------
class myViewController: UIViewController {

    var activityView: UIActivityIndicatorView = {
        let activity = UIActivityIndicatorView()
        activity.startAnimating()
        return activity
    }()

    @IBOutlet weak var searchTextField: myCustomTextField!

    //------------------------------------------------------------------------------
    // MARK: - Lifecycle
    //------------------------------------------------------------------------------
    override func viewDidLoad() {

        super.viewDidLoad()

        searchTextField.rightView = activityView
        searchTextField.rightViewMode = .never // Hide spinner
        searchTextField.clearButtonMode = .never // Hide clear button

        setupUIForTextEntry()
    }

    // ...
    // More code to switch between user text entry and "search progress" 
    // by calling setupUI... functions below
    // ...

    //------------------------------------------------------------------------------
    // MARK: - UI
    //------------------------------------------------------------------------------
    func setupUIForTextEntry() {

        // Hide spinner
        searchTextField.rightViewMode = .never

        // Show clear button
        searchTextField.clearButtonMode = .whileEditing
        searchTextField.becomeFirstResponder()
    }

    //------------------------------------------------------------------------------
    func setupUIForSearching() {

        // Show spinner
        searchTextField.rightViewMode = .always

        // Hide clear button
        searchTextField.clearButtonMode = .never
        searchTextField.resignFirstResponder()
    }

    //------------------------------------------------------------------------------

}

//------------------------------------------------------------------------------
Swany
  • 615
  • 8
  • 14
-1

Simple approach:

textField.rightViewMode = .always
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 25, height: 15))
textField.contentMode = .scaleAspectFit
imageView = UIImage(named: "imageName")
textField.rightView = imageView

Note: Height should be smaller than the width to allow horizontal padding.

Naresh
  • 16,698
  • 6
  • 112
  • 113
Mukesh Shakya
  • 425
  • 3
  • 9