Related
I have a login button which when clicked should show a loader. Here's what I have tried.
- (void)viewDidLoad {
loadingView.backgroundColor = [UIColor darkGrayColor];
loadingView.layer.cornerRadius = 5;
loader=[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
loader.frame = CGRectMake(13, 3, 80, 60);
[loader startAnimating];
loader.tag = 100;
[loadingView addSubview:loader];
UILabel* lblLoading = [[UILabel alloc]initWithFrame:CGRectMake(62, 15, 150, 30)];
lblLoading.text = #"Signing in...";
lblLoading.textColor = [UIColor whiteColor];
lblLoading.font = [UIFont fontWithName:lblLoading.font.fontName size:15];
lblLoading.textAlignment = NSTextAlignmentCenter;
[loadingView addSubview:lblLoading];
[self.view addSubview:loadingView];
loadingView.hidden = YES;
}
-(void)signinBtnPressed {
loadingView.hidden = NO;
//api code
}
But there is no loader loaded when utton is clicked.It shows after some time when the API is called
Can anyone tell me how to show the loader as soon as button is clicked or any other alternative.
I have an example of NVActivityIndicatorView. Please have a look.
NSObject class:
import UIKit
import NVActivityIndicatorView
class Helper: NSObject
{
class func createLoaderView(_ view : UIView) -> NVActivityIndicatorView
{
var ViewFrame : CGRect!
ViewFrame = CGRect(x: 0, y: 0, width: 60 , height: 60)
let center = CGPoint(x: (view.frame).midX, y: (view.frame).midY)
let activityIndicatorView = NVActivityIndicatorView(frame: ViewFrame, type: .ballSpinFadeLoader , color: UIColor(red: 200/255, green: 58/255, blue: 60/255, alpha:1.0), padding: CGFloat(0))
activityIndicatorView.center = center
activityIndicatorView.startAnimating()
return activityIndicatorView
}
class func removeLoaderView(_ activityIndicatorView : NVActivityIndicatorView)
{
activityIndicatorView.stopAnimating()
}
class func addBlurView(_ inView : UIView) -> UIVisualEffectView
{
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
//always fill the view
blurEffectView.frame = inView.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
blurEffectView.alpha = 0.5
return blurEffectView
}
}
In view controller where you want to show the loader call method of Helper class. Like:
import UIKit
import NVActivityIndicatorView
class ViewController: UIViewController,NVActivityIndicatorViewable
{
var activityIndicatorView : NVActivityIndicatorView!
var blurEffectView : UIVisualEffectView!
override func viewDidLoad()
{
super.viewDidLoad()
func showProgressView()
{
activityIndicatorView = Helper.createLoaderView(self.navigationController!.view)
blurEffectView = Helper.addBlurView((self.navigationController?.view)!)
self.navigationController!.view.addSubview(blurEffectView)
self.navigationController!.view.addSubview(activityIndicatorView)
}
func hideProgressView()
{
Helper.removeLoaderView(activityIndicatorView)
blurEffectView.removeFromSuperview()
}
}
}
Note: In order to show loader you have to call "showProgressView". Similarly to hide loader call hide method. To import ** NVActivityIndicatorView** you have to install pod 'NVActivityIndicatorView'.
As per your code you have not allocate loadingView
just allocate it and set frame or center like this way
loadingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
loadingView.center = self.view.center;
apurv, there is so many readymade external lib.s are available. But if you want your own customization, then can try this:
In AppDelegate
-(void)showActivityIndicatorWithTitle:(NSString *)title andUserInteraction:(BOOL)interaction
{
_hudView = [[UIView alloc] initWithFrame:CGRectMake((self.window.frame.size.width/2)-60, (self.window.frame.size.height/2)-60, 120, 120)];
_hudView.backgroundColor = [UIColor blackColor];
_hudView.alpha = 0.85f;
_hudView.clipsToBounds = YES;
_hudView.layer.cornerRadius = 10.0;
self.acivityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
self.acivityIndicator.frame = CGRectMake(40, 40, self.acivityIndicator.bounds.size.width, self.acivityIndicator.bounds.size.height);
[_hudView addSubview:self.acivityIndicator];
[self.acivityIndicator startAnimating];
_captionLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 80, 110, 40)];
_captionLabel.backgroundColor = [UIColor clearColor];
_captionLabel.textColor = [UIColor whiteColor];
_captionLabel.adjustsFontSizeToFitWidth = YES;
_captionLabel.numberOfLines = 0;
_captionLabel.lineBreakMode = NSLineBreakByWordWrapping;
_captionLabel.textAlignment = NSTextAlignmentCenter;
_captionLabel.font = [UIFont systemFontOfSize:12.0];
_captionLabel.text = title;
[_hudView addSubview:_captionLabel];
self.window.userInteractionEnabled = interaction;
[self.window addSubview:_hudView];
}
-(void)removeIndicator
{
self.window.userInteractionEnabled = YES;
[self.acivityIndicator removeFromSuperview];
[_captionLabel removeFromSuperview];
[_hudView removeFromSuperview];
}
set the property of _hudView, self.acivityIndicator and _captionLabel in AppDelegate.h file and add these two methods in .h file also.
use these two methods to add and remove the loader throughout the project when you need. Don't forget to instantiate the app delegate.
Thanks
Everything looks fine, you should post all code related to this view. I've created playground and looks like it's OK:
At the same time, I see no loadingView creation and [super viewDidLoad] call.
I have some trouble with my custom inputView for UITextFields. Depending on the text the user needs to input in a UITextField, the inputView displays only the needed letters. That means for short texts, an inputView with only one line of letters is sufficient, longer texts may require 2 or even 3 lines so the height of the inputView is variabel.
Since I was expecting better performance, there exists only one inputView instance that is used by every textField. That way the creation must only happen once and it made the sometimes needed direct access to the inputView easier. The inputView is set up in - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField, sets its required height and will be shown.
That works perfectly, but not on iOS8. There some system view containing the inputView will not update its frame to match the inputView's bounds when they are changed (first time works).
I know that can be fixed by using one instance of my inputView per textField. But I'm asking if there is a recommended/better way to adjust the frame or to report its change to the containing view. Maybe it is an iOS8 bug that could be fixed until release?
Here's some example code to reproduce the issue:
CustomInputView
#implementation CustomInputView
+ (CustomInputView*)sharedInputView{
static CustomInputView *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[CustomInputView alloc] init];
});
return sharedInstance;
}
- (id)init
{
self = [super init];
if (self) {
self.backgroundColor = [UIColor greenColor];
}
return self;
}
- (void)setupForTextField:(UITextField*)textField{
CGFloat height;
if(textField.tag == 1){
height = 100;
}else height = 50;
self.frame = CGRectMake(0, 0, 320, height);
}
#end
TestViewController code
- (void)viewDidLoad
{
[super viewDidLoad];
UITextField *tf = [[UITextField alloc] initWithFrame:CGRectMake(15, 50, 290, 30)];
tf.text = #"bigKeyboard";
tf.inputView = [CustomInputView sharedInputView];
tf.layer.borderWidth = 1;
tf.layer.borderColor = [UIColor lightGrayColor].CGColor;
tf.delegate = self;
tf.tag = 1;
[self.view addSubview:tf];
tf = [[UITextField alloc] initWithFrame:CGRectMake(15, 100, 290, 30)];
tf.text = #"smallKeyboard";
tf.inputView = [CustomInputView sharedInputView];
tf.layer.borderWidth = 1;
tf.layer.borderColor = [UIColor lightGrayColor].CGColor;
tf.delegate = self;
tf.tag = 2;
[self.view addSubview:tf];
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:#"dismissKeyboard" forState:UIControlStateNormal];
[button addTarget:self action:#selector(endEditing) forControlEvents:UIControlEventTouchUpInside];
button.frame = CGRectMake(15, 150, 290, 30);
[self.view addSubview:button];
}
- (void)endEditing{
[self.view endEditing:YES];
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
[[CustomInputView sharedInputView] setupForTextField:textField];
return YES;
}
I had similar issues with sizing a custom keyboard from iOS 8 to iOS 10. I believe the proper solution is to have the input view provide a proper intrinsicContentSize and change (and invalidate!) that value when you want to change the view's height. Sample code:
class CustomInputView: UIInputView {
var intrinsicHeight: CGFloat = 200 {
didSet {
self.invalidateIntrinsicContentSize()
}
}
init() {
super.init(frame: CGRect(), inputViewStyle: .keyboard)
self.translatesAutoresizingMaskIntoConstraints = false
}
required init?(coder: NSCoder) {
super.init(coder: coder)
self.translatesAutoresizingMaskIntoConstraints = false
}
override var intrinsicContentSize: CGSize {
return CGSize(width: UIViewNoIntrinsicMetric, height: self.intrinsicHeight)
}
}
class ViewController: UIViewController {
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
textView.becomeFirstResponder()
let inputView = CustomInputView()
// To make the view's size more clear.
inputView.backgroundColor = UIColor(red: 0.5, green: 1, blue: 0.5, alpha: 1)
textView.inputView = inputView
// To demonstrate a change to the view's intrinsic height.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(2)) {
inputView.intrinsicHeight = 400
}
}
}
See also https://stackoverflow.com/a/40359382/153354.
Another thing which I found critical for resizing an inputView on iOS 9 and up is setting allowsSelfSizing to true:
if #available(iOS 9.0, *) {
self.inputView?.allowsSelfSizing = true
}
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
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
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:
Create a new file that's a subclass of UITextField instead of the default NSObject
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;
}
You may have to import #import <QuartzCore/QuartzCore.h>
Add the rightViewRectForBounds method above
In Interface Builder, click on the TextField you would like to subclass and change the class attribute to the name of this new subclass
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];
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
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.
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 :)
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
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*/
}
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.
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];
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
}
}
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
Happy coding
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;
}
Here is one solution:
UIView *paddingTxtfieldView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 42)]; // what ever you want
txtfield.leftView = paddingTxtfieldView;
txtfield.leftViewMode = UITextFieldViewModeAlways;
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.
- (CGRect)rightViewRectForBounds:(CGRect)bounds
{
return CGRectMake(bounds.size.width - 40, 0, 40, bounds.size.height);
}
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.
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;
}
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!
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
}
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
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;
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!
Easiest way is just change the Textfield as RoundRect instead of Custom and see the magic. :)
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
...
...
textField.rightView = UIImageView(image: ...)
textField.rightView?.contentMode = .top
textField.rightView?.bounds.size.height += 10
textField.rightViewMode = .always
...
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()
}
//------------------------------------------------------------------------------
}
//------------------------------------------------------------------------------
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.
I know how to remove/change UISearchBar background color around search field:
[[self.searchBar.subviews objectAtIndex:0] removeFromSuperview];
self.searchBar.backgroundColor = [UIColor grayColor];
But don't know how to do this inside it like that:
This needs to be compatible with iOS 4.3+.
Just customize the text field itself.
I am simply doing this and it works fine for me (iOS 7).
UITextField *txfSearchField = [_searchBar valueForKey:#"_searchField"];
txfSearchField.backgroundColor = [UIColor redColor];
This way you don't need to create an image, size it, etc...
Details
Xcode Version 11.0 (11A420a), swift 5
UISearchBar customising sample
Solution
import UIKit
extension UISearchBar {
func getTextField() -> UITextField? { return value(forKey: "searchField") as? UITextField }
func setTextField(color: UIColor) {
guard let textField = getTextField() else { return }
switch searchBarStyle {
case .minimal:
textField.layer.backgroundColor = color.cgColor
textField.layer.cornerRadius = 6
case .prominent, .default: textField.backgroundColor = color
#unknown default: break
}
}
}
Usage
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 20, width: UIScreen.main.bounds.width, height: 44))
//searchBar.searchBarStyle = .prominent
view.addSubview(searchBar)
searchBar.placeholder = "placeholder"
searchBar.setTextField(color: UIColor.green.withAlphaComponent(0.3))
Result 1
searchBar.searchBarStyle = .prominent // or default
Result 2
searchBar.searchBarStyle = .minimal
Full sample
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 20, width: UIScreen.main.bounds.width, height: 44))
//searchBar.searchBarStyle = .minimal
searchBar.searchBarStyle = .prominent
view.addSubview(searchBar)
searchBar.placeholder = "placeholder"
searchBar.setTextField(color: UIColor.green.withAlphaComponent(0.3))
}
}
Solution which doesn't involve any private API ! :)
Currently (probably since iOS 5 ) you can do this, for simply one colour cases, in this way:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setBackgroundColor:[UIColor redColor]];
but please keep in mind that as it basis on appearance the change will be global for the app (it can be an advantage or a disadvantage of the solution).
For Swift you can use (it will work for iOS 9 and above):
if #available(iOS 9.0, *) {
UITextField.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).backgroundColor = UIColor.darkGrayColor()
}
You do not need #available if your project supports iOS 9 and newer.
If you need to support earlier versions of iOS and want to use Swift take a look at this question.
Use this code to change the searchBar's UITextField backgroundImage:
UITextField *searchField;
NSUInteger numViews = [searchBar.subviews count];
for (int i = 0; i < numViews; i++) {
if ([[searchBar.subviews objectAtIndex:i] isKindOfClass:[UITextField class]]) { //conform?
searchField = [searchBar.subviews objectAtIndex:i];
}
}
if (searchField) {
searchField.textColor = [UIColor whiteColor];
[searchField setBackground: [UIImage imageNamed:#"yourImage"]]; //set your gray background image here
[searchField setBorderStyle:UITextBorderStyleNone];
}
Use the below code to change the UISearchBarIcon:
UIImageView *searchIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"yourSearchBarIconImage"]];
searchIcon.frame = CGRectMake(10, 10, 24, 24);
[searchBar addSubview:searchIcon];
[searchIcon release];
Also, to change the searchBar icon you can use the following built-in method on UISearchBar (which is available from iOS 5+):
- (void)setImage:(UIImage *)iconImage forSearchBarIcon:(UISearchBarIcon)icon state:(UIControlState)state
Here you can set 4 types of UISearchBarIcon i.e.:
UISearchBarIconBookmark
UISearchBarIconClear
UISearchBarIconResultsList
UISearchBarIconSearch
I hope this help you...
According to the UISearchBar documentation:
You should use this function for iOS 5.0+.
- (void)setSearchFieldBackgroundImage:(UIImage *)backgroundImage forState:(UIControlState)state
Usage example:
[mySearchBar setSearchFieldBackgroundImage:myImage forState:UIControlStateNormal];
Sadly, in iOS 4 you need to revert to less sophisticated methods. See other answers.
As Accatyyc says for iOS5+ use setSearchFieldBackgroundImage, but you either need to create a graphic, or do the following:
CGSize size = CGSizeMake(30, 30);
// create context with transparent background
UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
// Add a clip before drawing anything, in the shape of an rounded rect
[[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0,0,30,30)
cornerRadius:5.0] addClip];
[[UIColor grayColor] setFill];
UIRectFill(CGRectMake(0, 0, size.width, size.height));
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.searchBar setSearchFieldBackgroundImage:image forState:UIControlStateNormal];
what about apple way?
UISearchBar.appearance().setSearchFieldBackgroundImage(myImage, for: .normal)
you can set any image on your design!
But if you want create all programmaticle, you ca do this
my solution on Swift 3
let searchFieldBackgroundImage = UIImage(color: .searchBarBackground, size: CGSize(width: 44, height: 30))?.withRoundCorners(4)
UISearchBar.appearance().setSearchFieldBackgroundImage(searchFieldBackgroundImage, for: .normal)
where i use helpers extension
public extension UIImage {
public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
color.setFill()
UIRectFill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let cgImage = image?.cgImage else { return nil }
self.init(cgImage: cgImage)
}
public func withRoundCorners(_ cornerRadius: CGFloat) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let rect = CGRect(origin: CGPoint.zero, size: size)
let context = UIGraphicsGetCurrentContext()
let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
context?.beginPath()
context?.addPath(path.cgPath)
context?.closePath()
context?.clip()
draw(at: CGPoint.zero)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
return image;
}
}
To do this on iOS 13+,
searchController.searchBar.searchTextField.backgroundColor = // your color here
Do note that by default the searchTextField.borderStyle is set to roundedRect, which applies a slight gray overlay on top of the color that you will set. If this is undesired, do
searchController.searchBar.searchTextField.borderStyle = .none
This will get rid of the gray overlay, but also get rid of the rounded corners.
I've found this to be the best way to customize the appearance of various search bar attributes in Swift 2.2 and iOS 8+ using UISearchBarStyle.Minimal
searchBar = UISearchBar(frame: CGRectZero)
searchBar.tintColor = UIColor.whiteColor() // color of bar button items
searchBar.barTintColor = UIColor.fadedBlueColor() // color of text field background
searchBar.backgroundColor = UIColor.clearColor() // color of box surrounding text field
searchBar.searchBarStyle = UISearchBarStyle.Minimal
// Edit search field properties
if let searchField = searchBar.valueForKey("_searchField") as? UITextField {
if searchField.respondsToSelector(Selector("setAttributedPlaceholder:")) {
let placeholder = "Search"
let attributedString = NSMutableAttributedString(string: placeholder)
let range = NSRange(location: 0, length: placeholder.characters.count)
let color = UIColor(white: 1.0, alpha: 0.7)
attributedString.addAttribute(NSForegroundColorAttributeName, value: color, range: range)
attributedString.addAttribute(NSFontAttributeName, value: UIFont(name: "AvenirNext-Medium", size: 15)!, range: range)
searchField.attributedPlaceholder = attributedString
searchField.clearButtonMode = UITextFieldViewMode.WhileEditing
searchField.textColor = .whiteColor()
}
}
// Set Search Icon
let searchIcon = UIImage(named: "search-bar-icon")
searchBar.setImage(searchIcon, forSearchBarIcon: .Search, state: .Normal)
// Set Clear Icon
let clearIcon = UIImage(named: "clear-icon")
searchBar.setImage(clearIcon, forSearchBarIcon: .Clear, state: .Normal)
// Add to nav bar
searchBar.sizeToFit()
navigationItem.titleView = searchBar
without using private API's:
for (UIView* subview in [[self.searchBar.subviews lastObject] subviews]) {
if ([subview isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField*)subview;
[textField setBackgroundColor:[UIColor redColor]];
}
}
For Changing Only Color :
searchBar.tintColor = [UIColor redColor];
For Applying Background Image :
[self.searchBar setSearchFieldBackgroundImage:
[UIImage imageNamed:#"Searchbox.png"]
forState:UIControlStateNormal];
A better solution is to set the appearance of the UITextField inside UISearchBar
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setBackgroundColor:[UIColor grayColor]];
try this in iOS13 in swift
#IBOutlet weak var searchBar: UISearchBar!
searchBar.barTintColor = .systemIndigo
searchBar.searchTextField.backgroundColor = .white
Just traverse all views using a category method (verified in iOS 7 and doesn't use private API):
#implementation UISearchBar (MyAdditions)
- (void)changeDefaultBackgroundColor:(UIColor *)color {
for (UIView *subview in self.subviews) {
for (UIView *subSubview in subview.subviews) {
if ([subSubview isKindOfClass:[UITextField class]]) {
UITextField *searchField = (UITextField *)subSubview;
searchField.backgroundColor = color;
break;
}
}
}
}
#end
So after importing the category into your class, just use it like:
[self.searchBar changeDefaultBackgroundColor:[UIColor grayColor]];
Keep in mind, if you put this immediately after the [[UISearchBar alloc] init] line, it won't work yet since the subviews of the search bar are still being created. Put it a few lines down after you setup the rest of the search bar.
- (void)viewDidLoad
{
[super viewDidLoad];
[[self searchSubviewsForTextFieldIn:self.searchBar] setBackgroundColor:[UIColor redColor]];
}
- (UITextField*)searchSubviewsForTextFieldIn:(UIView*)view
{
if ([view isKindOfClass:[UITextField class]]) {
return (UITextField*)view;
}
UITextField *searchedTextField;
for (UIView *subview in view.subviews) {
searchedTextField = [self searchSubviewsForTextFieldIn:subview];
if (searchedTextField) {
break;
}
}
return searchedTextField;
}
This is the Swift version ( swift 2.1 /IOS 9 )
for view in searchBar.subviews {
for subview in view.subviews {
if subview .isKindOfClass(UITextField) {
let textField: UITextField = subview as! UITextField
textField.backgroundColor = UIColor.lightGrayColor()
}
}
}
iOS 13, Swift 5
searchBar.searchTextField.backgroundColor = .gray
searchBar.searchTextField.tintColor = .white
searchBar.searchTextField.textColor = .white
Searchbar now has a new instance property SearchTextField starting iOS 13,
https://developer.apple.com/documentation/uikit/uisearchbar/3175433-searchtextfield
if(#available(iOS 13, *))
searchBar.searchTextField.backgroundColor = [UIColor whiteColor];
searchBar.searchTextField.textColor = [UIColor blackColor];
else{
//API that supports below iOS 13
//This will set it for all the UISearchBars in your application
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setBackgroundColor:[UIColor whiteColor]];
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setTextColor:[UIColor blackColor]];
}
For iOS 9 use this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Remove lag on oppening the keyboard for the first time
UITextField *lagFreeField = [[UITextField alloc] init];
[self.window addSubview:lagFreeField];
[lagFreeField becomeFirstResponder];
[lagFreeField resignFirstResponder];
[lagFreeField removeFromSuperview];
//searchBar background color change
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setBackgroundColor:[UIColor greenColor]];
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setTextColor:[UIColor blackColor];
return YES;
}
Swift 3
for subview in searchBar.subviews {
for innerSubview in subview.subviews {
if innerSubview is UITextField {
innerSubview.backgroundColor = UIColor.YOUR_COLOR_HERE
}
}
}
For Swift 3+, use this:
for subView in searchController.searchBar.subviews {
for subViewOne in subView.subviews {
if let textField = subViewOne as? UITextField {
subViewOne.backgroundColor = UIColor.red
//use the code below if you want to change the color of placeholder
let textFieldInsideUISearchBarLabel = textField.value(forKey: "placeholderLabel") as? UILabel
textFieldInsideUISearchBarLabel?.textColor = UIColor.blue
}
}
}
With Swift 4, I would recommend that you only do this, no additional code needed:
self.searchBar.searchBarStyle = .prominent
self.searchBar.barStyle = .black
You can also change .prominent to .minimal should you not want the outer background to be grey.
#EvGeniy Ilyin EvGeniy Ilyin's solution is the best.
I wrote an Objective-C version based on this solution.
Create a UIImage category, and advertise two class methods in UIImage+YourCategory.h
+ (UIImage *)imageWithColor:(UIColor *)color withSize:(CGRect)imageRect;
+ (UIImage *)roundImage:(UIImage *)image withRadius:(CGFloat)radius;
Implement methods in UIImage+YourCategory.m
// create image with your color
+ (UIImage *)imageWithColor:(UIColor *)color withSize:(CGRect)imageRect
{
UIGraphicsBeginImageContext(imageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, imageRect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
// get a rounded-corner image from UIImage instance with your radius
+ (UIImage *)roundImage:(UIImage *)image withRadius:(CGFloat)radius
{
CGRect rect = CGRectMake(0.0, 0.0, 0.0, 0.0);
rect.size = image.size;
UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect
cornerRadius:radius];
[path addClip];
[image drawInRect:rect];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Make your own UISearchBar in your ViewController
CGRect rect = CGRectMake(0.0, 0.0, 44.0, 30.0);
UIImage *colorImage = [UIImage imageWithColor:[UIColor yourColor] withSize:rect];
UIImage *finalImage = [UIImage roundImage:colorImage withRadius:4.0];
[yourSearchBar setSearchFieldBackgroundImage:finalImage forState:UIControlStateNormal];
This Worked for me.
- (void)setupSearchBar
{
[self.searchBar setReturnKeyType:UIReturnKeySearch];
[self.searchBar setEnablesReturnKeyAutomatically:NO];
[self.searchBar setPlaceholder:FOLocalizedString(#"search", nil)];
[self.searchBar setBackgroundImage:[UIImage new]];
[self.searchBar setBackgroundColor:[UIColor myGreyBGColor]];
[self.searchBar setBarTintColor:[UIColor myGreyBGColor]];
[self.searchBar setTintColor:[UIColor blueColor]];
}
Use it to update search textfield backgroud_color for xcode10 and xcode11 working fine for me
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setTextColor:[UIColor greenColor]];
This helped me to change the background color of textField in searchbar.
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).backgroundColor = .white
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?
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.
Create a textfield Custom
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)
}
}
Set padding for UITextField with UITextBorderStyleNone: Swift
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
}
}
}
^ these suggestions are great for those who are programmatically creating an interface.
But there are two LAZY EASY WAYS for those of us who use the Xcode interface builder:
easier: put a UIImageView behind a text field
easiest: change the border style on your to the simple black square (second from left option), then add your image as a background image. The image takes precedence over the square, so you still get the padding needed for a normal image background, without the square actually being drawn on.
EDIT: you can also use the black sphere (third from left option when selecting the UITextBox in IB), it does not work with the far right, "graphical sphere" style.
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.
Swift 3 Version:
class CustomTextField:UITextField{
required init?(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect.init(x: bounds.origin.x + 8, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return self.textRect(forBounds:bounds)
}
}
Nate Flink's answer is my favourite, but don't forget about right/left views.
E.g for UITextField subclass:
override func rightViewRectForBounds(bounds: CGRect) -> CGRect {
let rightViewBounds = super.rightViewRectForBounds(bounds)
return CGRectMake(CGRectGetMinX(rightViewBounds) - 10, CGRectGetMinY(rightViewBounds), CGRectGetWidth(rightViewBounds), CGRectGetHeight(rightViewBounds))
}
Above code set right padding for rightView of UITextField.
Swift 3 Solution
class CustomTextField: UITextField {
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 10, y: bounds.origin.y + 8, width: bounds.size.width - 20, height: bounds.size.height - 16)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return self.textRect(forBounds: bounds)
}
}
Here is a Swift code to give padding in UITextfield
func txtPaddingVw(txt:UITextField) {
let paddingView = UIView(frame: CGRectMake(0, 0, 10, 10))
txt.leftViewMode = .Always
txt.leftView = paddingView
}
and call using
self.txtPaddingVw(txtPin)
you can use category. set padding to left and right
UITextField+Padding.h
#interface UITextField (Padding)
#property (nonatomic, assign) CGFloat paddingValue;
#property (nonatomic, assign) CGFloat leftPadding;
#property (nonatomic, assign) CGFloat rightPadding;
//overwrite
-(CGRect)textRectForBounds:(CGRect)bounds;
-(CGRect)editingRectForBounds:(CGRect)bounds;
#end
UITextField+Padding.m
#import "UITextField+Padding.h"
#import <objc/runtime.h>
static char TAG_LeftPaddingKey;
static char TAG_RightPaddingKey;
static char TAG_Left_RightPaddingKey;
#implementation UITextField (Padding)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
-(CGRect)textRectForBounds:(CGRect)bounds {
CGFloat offset_Left=0;
CGFloat offset_Right=0;
if (self.paddingValue>0) {
offset_Left=self.paddingValue;
offset_Right=offset_Left;
}else{
if (self.leftPadding>0){
offset_Left=self.leftPadding;
}
if (self.rightPadding>0){
offset_Right=self.rightPadding;
}
}
if (offset_Left>0||offset_Right>0) {
return CGRectMake(bounds.origin.x+ offset_Left ,bounds.origin.y ,
bounds.size.width- (offset_Left+offset_Right), bounds.size.height-2 );
}else{
return bounds;
}
}
-(CGRect)editingRectForBounds:(CGRect)bounds {
return [self textRectForBounds:bounds];
}
#pragma clang diagnostic pop
#pragma maek -setter&&getter
- (CGFloat)paddingValue
{
return [objc_getAssociatedObject(self,&TAG_Left_RightPaddingKey) floatValue];
}
-(void)setPaddingValue:(CGFloat)paddingValue
{
objc_setAssociatedObject(self, &TAG_Left_RightPaddingKey, #(paddingValue), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(CGFloat)leftPadding
{
return [objc_getAssociatedObject(self,&TAG_LeftPaddingKey) floatValue];
}
-(void)setLeftPadding:(CGFloat)leftPadding
{
objc_setAssociatedObject(self, &TAG_LeftPaddingKey, #(leftPadding), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(CGFloat)rightPadding
{
return [objc_getAssociatedObject(self,&TAG_RightPaddingKey) floatValue];
}
-(void)setRightPadding:(CGFloat)rightPadding
{
objc_setAssociatedObject(self, &TAG_RightPaddingKey, #(rightPadding), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
you can set padding like this
self.phoneNumTF.paddingValue=10.f;
or
self.phoneNumTF.leftPadding=10.f;
#Evil trout's answer is great. I have been using this approach for quite a some time now. The only thing it lacks is "dealing with numerous text fields". I tried other approaches but does not seem to work.
Subclassing UITextField just to add a padding didn't make any sense to me. So, I iterated over all UITextFields to add the padding.
-(void) addPaddingToAllTextFields:(UIView*)view {
for(id currentView in [view subviews]){
if([currentView isKindOfClass:[UITextField class]]) {
// Change value of CGRectMake to fit ur need
[currentView setLeftView:[[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 20)]];
[currentView setLeftViewMode:UITextFieldViewModeAlways];
}
if([currentView respondsToSelector:#selector(subviews)]){
[textfieldarray addObjectsFromArray:[self addPaddingToAllTextFields:currentView]];
}
}
}
Brody's solution worked perfect for me. I have had to add side views on a textfield and add additional padding. So by implementing the custom UIEdgeInsets property to a UITextField subclass I have managed to achieve the task. I'm going to use this new subclass in all of my projects.
The best solution I found so far is a category. That's how I add a 5 points padding to left and right:
#implementation UITextField (Padding)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
- (CGRect)textRectForBounds:(CGRect)bounds {
return CGRectMake(bounds.origin.x + 5, bounds.origin.y,
bounds.size.width - 10, bounds.size.height);
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
return [self textRectForBounds:bounds];
}
#pragma clang diagnostic pop
#end
The #pragma's are just for removing the annoying warnings
textField.layer.borderWidth = 3;
will add border, which worked as padding for me.
I found it far easier to use a non-editable UITextView and set the contentOffset
uiTextView.contentOffset = CGPointMake(8, 7);