Button Click inside TableView Header is ignore in iOS - ios

I am making TableView with the custom Header. in the custom header I have 1 ImageView, 2 UILabel and 1 UIButton. When i set TouchUpInSide event on the UIButton it will not fire.
I see many post on the SO and google but nothing is getting help me.
Here What i have tried :
1). Swift - Custom TableView Not Executing Click on UIButton
2). UIButton in UITableView tableHeaderView not responding to touches
3). UIButton in a UITableView header ignores most touches
Here is my code for Custom header.
Code :
public override void ViewDidLoad()
{
base.ViewDidLoad();
TableView.Frame = new RectangleF((float)TableView.Frame.Left, 130, (float)TableView.Frame.Width, (float)(View.Frame.Size.Height - 130));
headerView = new UIView();
headerView.Frame = new CoreGraphics.CGRect(0, 0, TableView.Frame.Width, 140);
UIImageView backgroundImage = new UIImageView();
backgroundImage.Image = UIImage.FromFile("drawerbg");
backgroundImage.Frame = new CoreGraphics.CGRect(0, 0, TableView.Frame.Width, 140);
headerView.AddSubview(backgroundImage);
profileImage = new UIImageView();
profileImage.Frame = new CoreGraphics.CGRect(10, 10, 70, 70);
profileImage.Layer.CornerRadius = 35;
profileImage.ClipsToBounds = true;
profileImage.Image = UIImage.FromBundle("default_user");
backgroundImage.AddSubview(profileImage);
userName = new UILabel();
userName.Frame = new CoreGraphics.CGRect(10, 90, TableView.Frame.Width - 20, 20);
userName.Font = GargiFontAndSize.B14();
userName.TextColor = UIColor.White;
backgroundImage.AddSubview(userName);
userOrganization = new UILabel();
userOrganization.Frame = new CoreGraphics.CGRect(10, 110, TableView.Frame.Width - 50, 20);
userOrganization.Font = GargiFontAndSize.B14();
userOrganization.TextColor = UIColor.White;
userOrganization.Text = "Organizaton";
backgroundImage.AddSubview(userOrganization);
organizationArrowButton = new UIButton();
organizationArrowButton.Frame = new CoreGraphics.CGRect(260, 110, 20, 20);
organizationArrowButton.SetImage(UIImage.FromBundle("sort_down"), UIControlState.Normal);
organizationArrowButton.UserInteractionEnabled = true;
organizationArrowButton.ClipsToBounds = false;
backgroundImage.AddSubview(organizationArrowButton);
organizationArrowButton.BringSubviewToFront(headerView);
TableView.SectionHeaderHeight = 0;
TableView.SectionFooterHeight = 0;
var gradient = new CAGradientLayer();
gradient.Frame = headerView.Frame;
gradient.Colors = new CoreGraphics.CGColor[] { GargiColor.PrimaryColor().CGColor, GargiColor.SecondaryColor().CGColor };
headerView.Layer.InsertSublayer(gradient, 0);
TableView.TableHeaderView = headerView;
}
One more thing My viewController is extend DialogViewController.
Any Help will be Appreciated..

UIImageView's userInteraction is disabled by default, and you are adding button to image view, set userInteractionEnabled to true for UIImageView.

Related

Xamarin iOS adding Custom back button

I want to customise back-button so i can prompt user with confirmation box.
For that i have removed default navigation back button by setting its hidden property to 'True'
and i am adding new left bar button item.
But UI for the left bar button is not same as it is for default back button.
please find attached screenshot.
Please find below code for Left bar button added-
UIImage image = UIImage.FromBundle("BackButton"); UIButton customButton = new UIButton(UIButtonType.Custom);
customButton.SetImage(image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate),
UIControlState.Normal); customButton.Frame = new CGRect(0, 0,
100, 44); customButton.ImageEdgeInsets = new UIEdgeInsets(0,
-40, 0, -40); this.NavigationItem.SetHidesBackButton(true, false); var backButton = new
UIBarButtonItem(customButton);
this.NavigationItem.LeftBarButtonItem = backButton;
Thanks in advance !
You would better scale the image before you set the background image.
UIImage image = UIImage.FromBundle("BackButton").ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
UIImage newImg = ScalingImageToSize(image, new CGSize(30, 30)).ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
UIButton customButton = new UIButton(UIButtonType.Custom);
customButton.SetImage(newImg.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), UIControlState.Normal);
customButton.Frame = new CGRect(0, 0, 50, 50);
customButton.ImageEdgeInsets = new UIEdgeInsets(0, -40, 0, -40);
NavigationController.NavigationBar.BackIndicatorImage = newImg;
NavigationController.NavigationBar.BackIndicatorTransitionMaskImage = newImg;
UIBarButtonItem buttonItem = new UIBarButtonItem(customButton);
NavigationItem.BackBarButtonItem = buttonItem;
public UIImage ScalingImageToSize(UIImage sourceImage, CGSize newSize)
{
if (UIScreen.MainScreen.Scale == 2.0) //#2x iPhone 6 7 8
{
UIGraphics.BeginImageContextWithOptions(newSize, false, 2.0f);
}
else if (UIScreen.MainScreen.Scale == 3.0) //#3x iPhone 6p 7p 8p...
{
UIGraphics.BeginImageContextWithOptions(newSize, false, 3.0f);
}
else
{
UIGraphics.BeginImageContext(newSize);
}
sourceImage.Draw(new CGRect(0, 0, newSize.Width, newSize.Height));
UIImage newImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return newImage;
}
Option 2
You can create a custom navigationBar as you want .
public class xxxViewController: UIViewController
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
NavigationController.NavigationBar.Hidden = true;
double height = IsiphoneX();
UIView backView = new UIView()
{
BackgroundColor = UIColor.White,
Frame = new CGRect(0,20,UIScreen.MainScreen.Bounds.Width, height),
};
// set
UIButton backBtn = new UIButton() {
Frame = new CGRect(20, height-44, 40, 44),
Font = UIFont.SystemFontOfSize(18),
} ;
UIImage image = UIImage.FromBundle("BackButton");
UIImage newImg = ScalingImageToSize(image, new CGSize(30, 30));
backBtn.SetBackgroundImage(newImg.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate), UIControlState.Normal);
backBtn.AddTarget(this,new Selector("GoBack"),UIControlEvent.TouchUpInside);
UILabel titleLabel = new UILabel() {
Frame=new CGRect(UIScreen.MainScreen.Bounds.Width/2-75, 0,150, height),
Font = UIFont.SystemFontOfSize(20),
Text = "xxx",
TextColor = UIColor.Black,
Lines = 0,
};
UILabel line = new UILabel() {
Frame = new CGRect(0, height, UIScreen.MainScreen.Bounds.Width, 0.5),
BackgroundColor = UIColor.Black,
};
backView.AddSubview(backBtn);
backView.AddSubview(titleLabel);
backView.AddSubview(line);
View.AddSubview(backView);
}
double IsiphoneX()
{
double height = 44;
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
{
height = 64;
}
}
return height;
}
[Export("GoBack")]
void GoBack()
{
NavigationController.PopViewController(true);
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
NavigationController.NavigationBar.Hidden = false;
}
}
You can set the property of title , backButton and navigationBar as you need (such as text , color ,BackgroundColor ,font e.g.)

UITableView Interfering with Status Bar in Xamarin.iOS

I have created Slide Menu in Xamarin.iOS with below library https://github.com/thedillonb/MonoTouch.SlideoutNavigation
SplashViewController.cs
window = new UIWindow(UIScreen.MainScreen.Bounds);
Menu = new SlideoutNavigationController();
var storyboard = UIStoryboard.FromName("Main", null);
var webController = storyboard.InstantiateViewController("HomeViewController") as HomeViewController;
Menu.MainViewController = new MainNavigationController(webController, Menu);
Menu.MenuViewController = new MenuNavigationController(new DummyControllerLeft(), Menu) { NavigationBarHidden = true };
window.RootViewController = Menu;
window.MakeKeyAndVisible();
DummyControllerLeft.cs
public override void ViewDidLoad()
{
base.ViewDidLoad();
TableView.Frame = new RectangleF((float)TableView.Frame.Left, 30, (float)TableView.Frame.Width, (float)(View.Frame.Size.Height - 30));
headerView = new UIView();
headerView.Frame = new CoreGraphics.CGRect(0, 0, TableView.Frame.Width, 140);
profileImage = new UIImageView();
profileImage.Frame = new CoreGraphics.CGRect(10, 10, 70, 70);
profileImage.Layer.CornerRadius = 35;
profileImage.ClipsToBounds = true;
profileImage.Image = UIImage.FromBundle("gargi_logo.png");
userName = new UILabel();
userName.Frame = new CoreGraphics.CGRect(10, 90, TableView.Frame.Width - 20, 20);
userName.Font = GargiFontAndSize.B14();
userName.TextColor = UIColor.White;
headerView.AddSubview(userName);
userRole = new UILabel();
userRole.Frame = new CoreGraphics.CGRect(10, 110, TableView.Frame.Width - 20, 20);
userRole.Font = GargiFontAndSize.B14();
userRole.TextColor = UIColor.White;
headerView.AddSubview(userRole);
headerView.AddSubview(profileImage);
TableView.TableHeaderView = headerView;
TableView.ContentInset = new UIEdgeInsets(20, 0, 0, 0);
GetUserItemData();
SetSidePanel();
}
Its working fine.
Screen 1:
but when i scroll it is Interfering with Status Bar see below image.
Screen 2:
I have tried almost all solution or workaround but nothing is help to me. few of them are below.
Tried 1 :
TableView.ContentInset = new UIEdgeInsets(20, 0, 0, 0);
Tried 2 :
TableView.ScrollRectToVisible(new CGRect(0, 0, 1, 1), true);
Tried 3 :
EdgesForExtendedLayout = UIRectEdge.None;
ExtendedLayoutIncludesOpaqueBars = false;
AutomaticallyAdjustsScrollViewInsets = false;
I tried to solve this problem for last 6 hour but nothing is Help for me.
Any Help will be Appreciated.
If all of your menus 'rows' are in a single section, you could change your 'TableHeaderView' to a 'SectionHeader' that would remain in place whilst the section scrolls and should in theory solve your problem.
I think you will likely need to create a source delegate class for your tableview to do this though because the property isn't exposed for the tableview by itself, so you'd need to do something like this:
Assign it to your table view:
yoursource source = new yoursource();
TableView.Source = source;
Create the delegate class:
using CoreGraphics;
using Foundation;
using System;
using UIKit;
namespace somenamespace
{
class yoursource : UITableViewSource
{
public ThreadTableSource(UITableView table, List<ConversationThread> Threads)
{
}
public override UIView GetViewForHeader(UITableView tableView, nint section)
{
headerView = new UIView();
headerView.Frame = new CoreGraphics.CGRect(0, 0, tableView.Frame.Width, 140);
profileImage = new UIImageView();
profileImage.Frame = new CoreGraphics.CGRect(10, 10, 70, 70);
profileImage.Layer.CornerRadius = 35;
profileImage.ClipsToBounds = true;
profileImage.Image = UIImage.FromBundle("gargi_logo.png");
userName = new UILabel();
userName.Frame = new CoreGraphics.CGRect(10, 90, tableView.Frame.Width - 20, 20);
userName.Font = GargiFontAndSize.B14();
userName.TextColor = UIColor.White;
headerView.AddSubview(userName);
userRole = new UILabel();
userRole.Frame = new CoreGraphics.CGRect(10, 110, tableView.Frame.Width - 20, 20);
userRole.Font = GargiFontAndSize.B14();
userRole.TextColor = UIColor.White;
headerView.AddSubview(userRole);
headerView.AddSubview(profileImage);
return headerView;
}
}
}
Link to section header xamarin guide.

Customize Custom Cell further

I have the following class that generate custom cell. It works very well. However, I have a condition where I need to get more space for my InfoLabel than it is defined below. I could not able to handle it?
public WeinerGeneralCellItem (NSString cellId, Short Weiner) : base (UITableViewCellStyle.Default, cellId)
{
this.Weiner = Weiner;
weinerInfoLabel = new UILabel () {
TextColor = UIColor.FromRGB (0, 0, 0),
BackgroundColor = UIColor.Clear,
TextAlignment = UITextAlignment.Left,
};
weinerInfo = new UITextField () {
TextColor = UIColor.FromRGB (0, 0, 0),
TextAlignment = UITextAlignment.Right,
BackgroundColor = UIColor.Clear,
};
ContentView.Add (weinerInfoLabel);
ContentView.Add (weinerInfo);
}
public override void LayoutSubviews ()
{
base.LayoutSubviews ();
weinerInfoLabel.Frame = new CGRect(20, ContentView.Bounds.Height/4, 200, 25);
weinerInfo.Frame = new CGRect(220, ContentView.Bounds.Height/4, 300, 25);
}
}
By default infolabel width is 200, info is 300, but for the last cell, I want infoLabel width is 350, info is 150. I have tried the following but it did not work.
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
if (indexPath.Row == 5) {
cell.weinerInfoLabel.Frame = new CGRect(20, 20, 350, 25);
cell.weinerInfo.Frame = new CGRect(350, 20, 150, 25);
cell.weinerInfoLabel.Text = "The value calculated from the server";
cell.weinerInfo.Tag = 5;
cell.weinerInfo.Text = "155.00";
}
}
Here is the solution that I have ended up, it is working. I am just checking tag id before setting up the frame for that corresponding cell.
public override void LayoutSubviews ()
{
base.LayoutSubviews ();
if (weinerInfo.Tag == 5)
{
weinerInfoLabel.Frame = new CGRect (20, ContentView.Bounds.Height / 4, 350, 25);
weinerInfo.Frame = new CGRect (350, ContentView.Bounds.Height / 4, 170, 25);
}
else
{
weinerInfoLabel.Frame = new CGRect(20, ContentView.Bounds.Height/4, 200, 25);
weinerInfo.Frame = new CGRect (220, ContentView.Bounds.Height / 4, 300, 25);
}
}

How to change SeparatorColor of Selected Item in a UITableView

I've got the following UITableView
_navigationList = new UITableView
{
Source = UINavigationTableViewSource,
BackgroundColor = UIColor.FromRGB(43, 43, 43), // #2b2b2b - same as Android
SeparatorColor = UIColor.FromRGB(27,27,27), // #1b1b1b - same as Android
SeparatorInset = UIEdgeInsets.Zero,
ScrollEnabled = true
};
The UINavigationTableViewSource is using a custom UITableViewCell
public sealed class UINavigationTableViewCell : UITableViewCell
{
public new readonly UILabel TextLabel;
public UINavigationTableViewCell(string cellId)
: base(UITableViewCellStyle.Default, cellId)
{
TextLabel = new UILabel(new RectangleF(10, 0, Bounds.Width, 40)) {TextColor = UIColor.White}; // properly position the label.
SeparatorInset = UIEdgeInsets.Zero; // make the boarder go all the way across the list item
ContentView.BackgroundColor = UIColor.FromRGB(43, 43, 43); // #2b2b2b - same as Android
var activeOrb = new UIImageView(new RectangleF(0,0,10,Bounds.Height))
{
Image = UIImage.FromBundle("Images/active_orb.png"),
ContentMode = UIViewContentMode.ScaleAspectFit
};
SelectedBackgroundView = new UIView { BackgroundColor = UIColor.FromRGB(43, 43, 43) };
SelectedBackgroundView.Add(activeOrb);
ContentView.Add(TextLabel);
}
}
Everything is looking the way we want except for the ugly white line on a selected row.
How do I change the SeparatorColor when a row is selected?
I had never programmed in xamarin, but i worked on ios(5-7) sdk.
I would suggest you to dont use any seperators.Instead add the seperator line as view(height-1pixel;width-cellWidth) to your cell.
edit by ChaseFlorell - working example
_navigationList = new UITableView
{
Source = UINavigationTableViewSource,
BackgroundColor = UIColor.FromRGB(43, 43, 43), // #2b2b2b - same as Android
SeparatorStyle = UITableViewCellSeparatorStyle.None,
ScrollEnabled = true
};
Add(_navigationList);
public sealed class UINavigationTableViewCell : UITableViewCell
{
public new readonly UILabel TextLabel;
public UINavigationTableViewCell(string cellId) : base(UITableViewCellStyle.Default, cellId)
{
// The default state
TextLabel = new UILabel(new RectangleF(10, 0, Bounds.Width, 40)) { TextColor = UIColor.White }; // properly position the label.
ContentView.BackgroundColor = UIColor.FromRGB(43, 43, 43); // #2b2b2b - same as Android
ContentView.Add(Separator(Bounds));
ContentView.Add(TextLabel);
// todo: move colors to a config file.
// The selected state
var activeOrb = new UIImageView(new RectangleF(0, 0, 10, Bounds.Height))
{
Image = UIImage.FromBundle("Images/active_orb.png"),
ContentMode = UIViewContentMode.ScaleAspectFit
};
SelectedBackgroundView = new UIView { BackgroundColor = UIColor.FromRGB(43, 43, 43) };
SelectedBackgroundView.Add(Separator(Bounds));
SelectedBackgroundView.Add(activeOrb);
}
private static UIView Separator(RectangleF bounds)
{
return new UIView(new RectangleF(0, 0, bounds.Width, 1))
{
BackgroundColor = UIColor.FromRGB(27, 27, 27)
};
}
}

UITextfield leftView/rightView padding on iOS7

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.

Resources