Custom inputView with dynamic height in iOS 8 - ios

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
}

Related

adding loader at login button

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.

JBChartView how to add a label to each bar? (Swift)

I'm using the JBChartView library to draw a bar chart in my iOS application. Each Bar should have an identifier, that is shown at the bottom of the bar.
I tried defining a custom barView with an additional label, but do not know how to place the label relative to the bar.
Here's the code:
func barChartView(barChartView: JBBarChartView!, barViewAtIndex index: UInt) -> UIView! {
let barView = UIView()
// setting up the bar
let bar: Float = chartData[Int(index)]
var barColor = UIColorFromRGB(0xE8E8E8)
if bar >= 1 { barColor = UIColorFromRGB(0xFF6259) }
if bar > 33 { barColor = UIColorFromRGB(0xFFC02F) }
if bar > 66 { barColor = UIColorFromRGB(0x28CA41) }
barView.backgroundColor = barColor
// setting up the label
var label = UILabel()
label.textAlignment = NSTextAlignment.Center
label.textColor = barColor
label.text = NSString(format: "%.0f", bar)
barview.addSubview(label)
return barView
}
Your help would be much appreciated!
ok, this is embarassing: label and bar had the same color, so the label was there all the time .
The final code (improved and with an additional Data Label):
func barChartView(barChartView: JBBarChartView!, barViewAtIndex index: UInt) -> UIView! {
let barView = BarChartBarView()
let bar: Float = chartData[Int(index)]
var barColor = UIColorFromRGB(0xE8E8E8)
if bar >= 1 { barColor = UIColorFromRGB(0xFF6259) }
if bar > 33 { barColor = UIColorFromRGB(0xFFC02F) }
if bar > 66 { barColor = UIColorFromRGB(0x28CA41) }
barView.backgroundColor = barColor
barView.dataLabel.text = NSString(format: "%.0f", bar)
barView.legendLabel.text = chartLegend[Int(index)]
return barView
}
class BarChartBarView: UIView {
let labelFont = UIFont(name:"Raleway-Thin", size:8.0)
var padding = CGFloat(0)
var barWidth = CGFloat(27)
var dataLabel = UILabel()
var legendLabel = UILabel()
var legendLabelWidth = CGFloat(50)
var labelHeight = CGFloat(27)
override convenience init() {
self.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
}
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColorFromRGB(0xE8E8E8)
// setting up data Label
dataLabel.frame = CGRectMake(0, 0, barWidth, labelHeight)
dataLabel.textAlignment = NSTextAlignment.Center
dataLabel.textColor = UIColor.whiteColor()
dataLabel.font = labelFont
self.addSubview(dataLabel)
// setting up legend Label
legendLabel.frame = CGRectMake(0, self.bounds.height, legendLabelWidth, labelHeight)
legendLabel.textAlignment = NSTextAlignment.Center
legendLabel.textColor = UIColor.blackColor()
legendLabel.font = labelFont
self.addSubview(legendLabel)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
let xOffset = (self.barWidth - self.legendLabelWidth) / 2
let yOffset:CGFloat = self.bounds.height
let width = self.legendLabelWidth
let height = self.labelHeight
self.legendLabel.frame = CGRectMake(xOffset, yOffset, width, height)
}
}
#Armin
I got the clue to implement the following method:
- (UIView *)barChartView:(JBBarChartView *)barChartView barViewAtIndex:(NSUInteger)index
From Armin. Because even though JawBone's JBBarChart library is impressive their Demo is totally done using code, and also it's bit confusing at a glance. However my way of adding the Label view is same old way of creating a UIView and adding the UILabel as a subview and returning it. And it looks like follows:
- (UIView *)barChartView:(JBBarChartView *)barChartView barViewAtIndex:(NSUInteger)index {
UIView *barView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 55, (CGFloat)chartData[(int)index])];
if (index == 0) {
[barView setBackgroundColor:[UIColor grayColor]];
} else if (index == 1) {
[barView setBackgroundColor:[UIColor redColor]];
} else if (index == 2) {
[barView setBackgroundColor:[UIColor orangeColor]];
} else {
[barView setBackgroundColor:[UIColor blueColor]];
}
int roomCount = (int)chartData[(int)index];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(2, 5.0f, 50.0f, 21.0f)];
[label setTextAlignment:NSTextAlignmentCenter];
[label setTextColor:[UIColor blackColor]];
[label setFont:[UIFont fontWithName:#"Raleway-Thin" size:6.0]];
[label setText:[NSString stringWithFormat:#"%d/56", roomCount]];
[barView addSubview:label];
return barView;
}
Please consider that chartData is contains my data, as integers. So I need the height of each Bar View according to that integer in each position.
Hope this answer would be helpful to someone out there, specially who is juggling to do this implementation in Objective-C.
Cheers!

Padding Placeholder text ios

I want to make the placeholder text display in middle of the textfield (Padding placeholder text). The size of the placeholder text also needs to increase. My code is as follows, how can i solve this ?
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(30, 220,250,55)];
textField.placeholder=#"iiiiiii";
UIView *padView = [[UIView alloc] initWithFrame:CGRectMake(10, 110, 10, 0)];
textField.leftView = padView;
textField.leftViewMode = UITextFieldViewModeAlways;
[self.view addSubview:textField];
UPDATE
I want the font size of the placeholder text to increase your name, and it should have a Left padding to it.
You could subclass your UITextFiled and override methods:
MyTextField.m
- (CGRect)textRectForBounds:(CGRect)bounds {
return [self rectForBounds:bounds];
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
return [self rectForBounds:bounds];
}
- (CGRect)placeholderRectForBounds:(CGRect)bounds {
return [self rectForBounds:bounds];
}
//here 40 - is your x offset
- (CGRect)rectForBounds:(CGRect)bounds {
return CGRectInset(bounds, 40, 3);
}
upd:
also set
textFiled.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
because it could some problems with io6 vs ios 7 vertical positionning
Same question was being asked and answered as below Set padding for UITextField with UITextBorderStyleNone
UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
textField.leftView = paddingView;
textField.leftViewMode = UITextFieldViewModeAlways;
You can set the starting text alignment (of the textField from xib or via code) to be center aligned.
Then in the -textFieldShouldBeginEditing, you can set the textField to be left aligned.
Similarly, on the -textFieldDidEndEditing, check if the textField is empty and if it is then set textField back to center aligned.
basically:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
[textField setTextAlignment:NSTextAlignmentLeft];
return YES;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
if(textField.text.length == 0) {
[textField setTextAlignment:NSTextAlignmentCenter];
}
}
EDIT::
the .h of your ViewController class should look like:
#interface ViewController : UIViewController <UITextFieldDelegate>
{
UITextField *myTextField;
}
now, replace your other code with this:
myTextField = [[UITextField alloc] initWithFrame:CGRectMake(30, 220,250,55)];
myTextField.placeholder=#"iiiiiii";
//important
[myTextField setDelegate: self];
//commented lines not really needed
//UIView *padView = [[UIView alloc] initWithFrame:CGRectMake(10, 110, 10, 0)];
//textField.leftView = padView;
//textField.leftViewMode = UITextFieldViewModeAlways;
[self.view addSubview:textField];
sampleTextfield.leftView = UIView(frame: CGRectMake(0, 0, 20, self.sampleTextfield.frame.height))
sampleTextfield.leftViewMode = UITextFieldViewMode.Always
The easiest way that I found to do this task on swift 2 and Xcode 7:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var emailTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let paddingView = UIView(frame: CGRectMake(0, 0, 25, self.emailTextField.frame.height))
emailTextField.leftView = paddingView
emailTextField.leftViewMode = UITextFieldViewMode.Always
}
}
func placeholderPadding(textField:UITextField, leftPadding:CGFloat) {
textField.leftView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: leftPadding, height: textField.frame.height))
textField.leftViewMode = UITextFieldViewMode.always
}
While I have not specifically tested it, this should work:
self.YourTextField.attributedPlaceholder = NSAttributedString(string: " YourText")
Add the amount of blank spaces (padding) to your string

How to change inside background color of UISearchBar component on iOS

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

Set padding for UITextField with UITextBorderStyleNone

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);

Resources