I have created a custom view and added a UITextField to it.My question is: How can I add a delegate so that the you can set it as the default cmd+drag behaviour of XCode?
My current attempt is by doing something like this:
In my .h file:
#import <UIKit/UIKit.h>
IB_DESIGNABLE
#interface CustomTextField : UIView
#property (assign, nonatomic) IBInspectable id textFieldDelegate;
#end
and my .m file:
#import "CustomTextField.h"
#interface CustomTextField()
#property (strong, nonatomic) IBOutlet UITextField *textField;
#end
#implementation CustomTextField
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
[self loadNib];
}
return self;
}
- (void)loadNib{
UIView *view = [[[NSBundle bundleForClass:[self class]] loadNibNamed:#"CustomTextField" owner:self options:nil] firstObject];
[self addSubview:view];
view.frame = self.bounds;
}
- (void)setTextFieldDelegate:(id)textFieldDelegate{
self.textField.delegate = textFieldDelegate;
}
#end
But it doest show up in the left panel of XCode, Connections Inspector Tab.
Also here is my current code.
Update 1:
also if using the code below I get a an error:
- (id)initWithFrame:(CGRect)aRect
{
self = [super initWithFrame:aRect];
if (self)
{
[self loadNib];
}
return self;
}
- (id)initWithCoder:(NSCoder*)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self loadNib];
}
return self;
}
- (void)loadNib{
//
// UIView *view = [[[NSBundle bundleForClass:[self class]] loadNibNamed:#"CustomTextField" owner:self options:nil] firstObject];
// [self addSubview:view];
// view.frame = self.bounds;
UIView *view = [[[NSBundle bundleForClass:[self class]] loadNibNamed:#"CustomTextField" owner:self options:nil] firstObject];
[view setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:view];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[view]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[view]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)]];
self.textLabel.text = #"1";
}
Any suggestions on what should I do?
Update 2
I ended up by replacing the initWithFrame, initWithCoder and loadNib functions with:
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder
{
if (![self.subviews count])
{
NSBundle *mainBundle = [NSBundle mainBundle];
NSArray *loadedViews = [mainBundle loadNibNamed:#"CustomTextField" owner:nil options:nil];
CustomTextField *loadedView = [loadedViews firstObject];
loadedView.frame = self.frame;
loadedView.autoresizingMask = self.autoresizingMask;
loadedView.translatesAutoresizingMaskIntoConstraints =
self.translatesAutoresizingMaskIntoConstraints;
for (NSLayoutConstraint *constraint in self.constraints)
{
id firstItem = constraint.firstItem;
if (firstItem == self)
{
firstItem = loadedView;
}
id secondItem = constraint.secondItem;
if (secondItem == self)
{
secondItem = loadedView;
}
[loadedView addConstraint:
[NSLayoutConstraint constraintWithItem:firstItem
attribute:constraint.firstAttribute
relatedBy:constraint.relation
toItem:secondItem
attribute:constraint.secondAttribute
multiplier:constraint.multiplier
constant:constraint.constant]];
}
return loadedView;
}
return self;
}
Related
I have 4 screens that have one almost the same view:
And one screen have the same view but with slightly different UI:
So, my question: Can I use one xib and adapt states (active, inactive) and change ui for different screen? How I can do it?
Here is an example of this kind of class
In Your .m file of custom XIB class if you are using objective-c.
- (void)foo:(NSString*)labelText andButtonText:(NSString*)buttonTitle {
//Do your code here for some screen like change labels and button text
}
- (void)bar:(NSString*)labelText andButtonText:(NSString*)buttonTitle {
//Do your code here for some another screen and change labels and button text
}
In Your .h file of custom XIB class if you are using objective-c.
- (void)foo:(NSString*)labelText andButtonText:(NSString*)buttonTitle;
- (void)bar:(NSString*)labelText andButtonText:(NSString*)buttonTitle;
In your view controller where you want to display the custom UI
Create an instance of your xib or add through interfacebuilder
And On your instance of custom class call the method as required.
Below is a class I've used in one of my project to get a clear understanding.
#import <UIKit/UIKit.h>
#import "DYRateView.h"
#interface LevelAndRankDetails : UIView
#property (nonatomic, strong) IBOutlet UIView* contentView;
#property (nonatomic, strong) IBOutlet UIView* viewContainer;
#property (nonatomic, strong) IBOutlet UILabel* lblLevel;
#property (nonatomic, strong) IBOutlet UILabel* lblRanking;
#property (weak, nonatomic) IBOutlet DYRateView *viewRate;
- (void)setLevel:(NSNumber*)level andRanking:(NSNumber*)ranking;
- (void)setupUI;
#end
.m File
#import "LevelAndRankDetails.h"
#import "AppDelegate.h"
#import "Constants.h"
#implementation LevelAndRankDetails
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]){
[self commonSetup];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self commonSetup];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
}
- (void)viewFromNibForClass {
[[NSBundle mainBundle] loadNibNamed:[[self class] description] owner:self options:nil];
[self addSubview:self.contentView];
self.contentView.frame = self.bounds;
}
- (void)commonSetup {
[self viewFromNibForClass];
//For View's Corner Radius
self.contentView.layer.cornerRadius = 12;
self.contentView.layer.masksToBounds = YES;
self.contentView.backgroundColor = kDefaultBackgroundGreyColor;
self.viewContainer.backgroundColor = kDefaultBackgroundGreyColor;//[UIColor clearColor];
self.backgroundColor = kDefaultBackgroundGreyColor;
//self.viewContainer.backgroundColor = UIColorFromRGB(0xBB9657);//[kLearnFromLightColor colorWithAlphaComponent:0.5];
self.viewRate.rate = 0;
self.viewRate.editable = NO;
self.viewRate.delegate = nil;
self.viewRate.alignment = RateViewAlignmentCenter;
self.viewRate.backgroundColor = [UIColor clearColor];
[self.viewRate setEmptyStarImage:[UIImage imageNamed:#"StarEmpty"]];
UIImage* imageFullStar = [[UIImage imageNamed:#"StarFull"] imageTintedWithColor:kSliderDarkYellowColor];
[self.viewRate setFullStarImage:imageFullStar];
self.lblLevel.textColor = [UIColor whiteColor];
self.lblRanking.textColor = [UIColor whiteColor];
//For Teacher label
}
- (void)setupUI {
self.contentView.layer.cornerRadius = 0;
self.contentView.layer.masksToBounds = YES;
self.contentView.backgroundColor = [UIColor clearColor];
self.viewContainer.backgroundColor = [UIColor clearColor];//[UIColor clearColor];
self.backgroundColor = [UIColor clearColor];
}
- (void)setRanking:(CGFloat)ranking {
self.viewRate.rate = ranking;
}
- (void)setLevel:(NSNumber*)level {
self.lblLevel.text = [NSString stringWithFormat:#"Level : %#",level];
}
- (void)setLevel:(NSNumber*)level andRanking:(NSNumber*)ranking {
if (level.integerValue > 0) {
[self setLevel:level];
}
if (ranking.doubleValue > 0) {
CGFloat rankingConverted = ranking.floatValue;
[self setRanking:rankingConverted];
}
}
#end
And this is how you use it in your view controller
LevelAndRankDetails* toolTipCustomView = [[LevelAndRankDetails alloc] initWithFrame:CGRectMake(0, 0, 250, 66)];
toolTipCustomView.backgroundColor = [UIColor blackColor];
[toolTipCustomView setLevel:#(10) andRanking:#(3)];
I have a custom view called TimeTooltipView. Here is the code:
TimeTooltipView.h
#import <UIKit/UIKit.h>
#interface TimeTooltipView : UIView
#property (weak, nonatomic) IBOutlet UILabel *timeLabel;
-(void)configureView;
#end
TimeTooltipView.m
#import "TimeTooltipView.h"
#implementation TimeTooltipView
-(id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:#"TimeTooltipView" owner:self options:nil];
UIView *mainView = [subviewArray objectAtIndex:0];
[self addSubview:mainView];
[self configureView];
}
return self;
}
-(void)configureView {
self.backgroundColor = [UIColor greenColor];
}
#end
I add a TimeTooltipView in a view controller, like so:
TimeTooltipView *timeTooltipView = [[TimeTooltipView alloc]
initWithFrame: CGRectMake(100, 100, 50, 50)];
timeTooltipView.timeLabel.text = #"TEST";
[self.view addSubview:timeTooltipView];
timeTooltipView.timeLabel.text = #"TEST2";
I need to change timeLabel's text on the fly from the view controller. Using the code above, the view gets added and has a green background color. But the label text never changes to "TEST" or "TEST2".
How can I change the custom view's label text on the fly?
-(id)initWithFrame:(CGRect)frame {
NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:#"TimeTooltipView" owner:self options:nil];
//Instead of making it subView just replace it.
self = [subviewArray objectAtIndex:0];
self.frame = frame;
[self configureView];
return self;
}
-(void)configureView {
self.backgroundColor = [UIColor greenColor];
}
Hi i am very new for ios and in my app i am loading UIView using .xib files
when i click first buttons i want to load FirstView and remove otherviews
when i click second button i want to load SecondView and remove otherviews
when i click third button i want to load ThirdView and remove otherviews
mycode:-
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize leftView,rightView;
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)FirstAction:(id)sender {
FirstView * test1 = [[FirstView alloc]initWithFrame:CGRectMake(0, 0, rightView.frame.size.width, rightView.frame.size.height)];
test1.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[rightView addSubview:test1];
}
- (IBAction)SecondAction:(id)sender {
SecondView * test2 = [[SecondView alloc]initWithFrame:CGRectMake(0, 0, rightView.frame.size.width, rightView.frame.size.height)];
test2.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[rightView addSubview:test2];
}
- (IBAction)ThirdAction:(id)sender {
ThirdView * test3 = [[ThirdView alloc]initWithFrame:CGRectMake(0, 0, rightView.frame.size.width, rightView.frame.size.height)];
test3.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[rightView addSubview:test3];
}
#end
Try this piece of code: I have written code for view which will remove previous view before adding the new one.
#import "ViewController.h"
#interface ViewController ()
{
FirstView * test1;
SecondView * test2;
ThirdView * test3;
}
#end
#implementation ViewController
#synthesize leftView,rightView;
- (void)viewDidLoad {
[super viewDidLoad];
test1 = [[[NSBundle mainBundle] loadNibNamed:#"FirstView" owner:self options:nil] objectAtIndex:0];
test2 = [[[NSBundle mainBundle] loadNibNamed:#"SecondView" owner:self options:nil] objectAtIndex:0];
test3 = [[[NSBundle mainBundle] loadNibNamed:#"ThirdView" owner:self options:nil] objectAtIndex:0];
}
- (IBAction)FirstAction:(id)sender {
test1.frame = CGRectMake(0, 0, rightView.frame.size.width, rightView.frame.size.height);
test1.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self removePreviousView:test1 FromSuperView:rightView];
[rightView addSubview:test1];
}
- (IBAction)SecondAction:(id)sender {
test2.frame = CGRectMake(0, 0, rightView.frame.size.width, rightView.frame.size.height);
test2.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self removePreviousView:test2 FromSuperView:rightView];
[rightView addSubview:test2];
}
- (IBAction)ThirdAction:(id)sender {
test3.frame = CGRectMake(0, 0, rightView.frame.size.width, rightView.frame.size.height);
test3.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self removePreviousView:test3 FromSuperView:rightView];
[rightView addSubview:test3];
}
- (void)removePreviousView:(UIView*)previousView FromSuperView:(UIView*)view{
for (UIView *subView in view.subviews) {
if (![subView isKindOfClass:[previousView class]]) {
[subView removeFromSuperview];
}
}
}
#end
1)
Make view global
FirstView * test1;
SecondView * test2;
ThirdView * test3;
Remove from superview whenever you want:
[test1 removeFromSuperView];
2) Add tag to view
test1.tag = 10;
Remove view using tag value:
[(UIView*)[rightView viewWithTag:10] removeFromSuperview];
Use this code. It contains a loadXib: call that loads the view from the nib with the given name and returns it.
#interface ViewController ()
{
FirstView * test1;
SecondView * test2;
ThirdView * test3;
}
#end
#implementation ViewController
#synthesize leftView,rightView;
- (void)viewDidLoad {
[super viewDidLoad];
}
-(UIView*)loadXib:(NSString *)name
{
UINib *nib = [UINib nibWithNibName:name bundle:nil];
if (nib != nil)
{
NSArray *items = [nib instantiateWithOwner:self options:nil];
if (items != nil && items.count == 1)
{
return (UIView*)items[0];
}
}
return nil;
}
- (IBAction)FirstAction:(id)sender {
// test1 = [[FirstView alloc]initWithFrame:CGRectMake(0, 0, rightView.frame.size.width, rightView.frame.size.height)];
test1 = (FirstView*)[self loadXib:#"FirstView"];
if (test1 != nil) {
test1.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[rightView.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
[rightView addSubview:test1];
}
}
- (IBAction)SecondAction:(id)sender {
// test2 = [[SecondView alloc]initWithFrame:CGRectMake(0, 0, rightView.frame.size.width, rightView.frame.size.height)];
test2 = (SecondView*)[self loadXib:#"SecondView"];
if (test2 != nil) {
test2.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[rightView.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
[rightView addSubview:test2];
}
}
- (IBAction)ThirdAction:(id)sender {
// test3 = [[ThirdView alloc]initWithFrame:CGRectMake(0, 0, rightView.frame.size.width, rightView.frame.size.height)];
test3 = (ThirdView*)[self loadXib:#"ThirdView"];
if (test3 != nil ) {
test3.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[rightView.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
[rightView addSubview:test3];
}
}
#end
Below is method for your need.
/* Without tag */
- (void)removeSubviewsExpectView:(id)viewClass {
for (UIView *subView in self.view.subviews) {
if (![subView isKindOfClass:[viewClass class]]) {
[subView removeFromSuperview];
}
}
}
/* With tag */
- (void)removeSubviewsExpectView:(int)viewTag {
for (UIView *subView in self.view.subviews) {
if (subView.tag != viewTag) {
[subView removeFromSuperview];
}
}
}
Hope this helps you out.
Firstly you create UiView IBOutlets in the NSBundle then you choose this method
- (IBAction)FirstAction:(id)sender {
NSArray *viewsToRemove = [rightView subviews];
for (UIView *v in viewsToRemove) {
[v removeFromSuperview];
}
UIView *firstViewUIView = [[[NSBundle mainBundle] loadNibNamed:#"Test1" owner:self options:nil] firstObject];
[rightView containerView addSubview:firstViewUIView];
}
- (IBAction)SecondAction:(id)sender {
NSArray *viewsToRemove = [rightView subviews];
for (UIView *v in viewsToRemove) {
[v removeFromSuperview];
}
UIView *secondView = [[[NSBundle mainBundle] loadNibNamed:#"Test2" owner:self options:nil] firstObject];
[rightView containerView addSubview:seconView];
}
- (IBAction)ThirdAction:(id)sender {
NSArray *viewsToRemove = [rightView subviews];
for (UIView *v in viewsToRemove) {
[v removeFromSuperview];
}
UIView *thirdView = [[[NSBundle mainBundle] loadNibNamed:#"Test3" owner:self options:nil] firstObject];
[rightView containerView addSubview:thirdView];
}
I have created MyCustomView.xib/h/m: which extends UIView class. Then in my Main.storyboard, put UIView object, changed the class to MyCustomView and linked to MainController.h. So, MainController contains reference to MyCustomView instance.
For loading from xib, in MyCustomView I do the following:
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
if (self.subviews.count == 0) {
[self commonInit];
}
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (void) stretchToSuperView:(UIView*)view
{
view.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *bindings = NSDictionaryOfVariableBindings(view);
NSString *formatTemplate = #"%#:|[view]|";
for (NSString * axis in #[#"H",#"V"]) {
NSString * format = [NSString stringWithFormat:formatTemplate,axis];
NSArray * constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:bindings];
[view.superview addConstraints:constraints];
}
}
- (void)commonInit
{
MyCustomView* view = nil;
NSArray *views = [[NSBundle mainBundle] loadNibNamed:#"MyCustomView" owner:self options:nil];
view = views.firstObject;
[self addSubview:view];
[self stretchToSuperView:views.firstObject];
}
This works quite well, until I want to declare delegate in MyCustomView in order to notify MainController to any change(button click, etc). So, my ManController conforms MyCustomViewDelegate and implements methods.
EDIT 1 setting delegate
//MainViewController.m file
#interface MainViewController ()
#property (strong, nonatomic) IBOutlet MyCustomView *customView;
#end
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.customView.delegate = self;
}
The problem here is that delegate becomes nil and I don't understand the reason, so don't know what's the mistake.
Edit 2 I think somehow I have 2 different instances of MyCustomView.
I have added new property in MyCustomView:
#interface MyCustomView : UIView
#property (weak, nonatomic) IBOutlet UIButton *firstItem;
#property(nonatomic, weak)id <MyCustomViewDelegate> delegate;
// this is test property
#property(nonatomic, assign)int testProperty;
#end
And when I set this property in viewDidLoad and then click to first button, I see that testProperty has value 0. So, this could mean something wrong with IBOutlet MyCustomView *customView.
You are correct, that you have two view objects. The one that you added to the storyboard and the one you created via loadNibNamed.
Bottom line, loadNibNamed will create the view for you (assuming that you've specified MyCustomView as the base class for the view specified in the NIB; you can leave NIB's "File owner" blank). You can then write a convenience method in MyCustomView to instantiate the NIB-based view:
+ (instancetype)myCustomViewWithDelegate:(id<MyCustomViewDelegate>)delegate {
NSArray *array = [[NSBundle mainBundle] loadNibNamed:#"MyCustomView" owner:delegate options:nil];
MyCustomView *view = array.firstObject;
NSAssert([view isKindOfClass:[MyCustomView class]], #"Base class of NIB's top level view is not MyCustomView");
view.delegate = delegate;
return view;
}
Then, rather than specifying the view on the storyboard, you must instantiate and add it to the view hierarchy programmatically, e.g.:
- (void)viewDidLoad {
[super viewDidLoad];
MyCustomView *view = [MyCustomView myCustomViewWithDelegate:self]; // since `self.myCustomView` should be `weak`, let's hold the view in local variable
[self.view addSubview:view];
self.myCustomView = view; // then set the property after the view is safely added to view hierarchy
NSDictionary *views = #{#"myCustomView" : self.myCustomView};
self.myCustomView.translatesAutoresizingMaskIntoConstraints = false;
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[myCustomView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[myCustomView]|" options:0 metrics:nil views:views]];
// ...
}
Obviously, when adding a view programmatically, you have to specify its frame and autoresizingMask, or use constraints like shown above.
Unfortunately, I can't make a simple comment, so I have to ask, and give advices as 'answer'.
First of all, I don't see where do you set the delegate to your MainController, but I think in the viewDidLoad() of the controller.
Second thing. It's really important how do you setup your MyCustomView.xib, because you create a brand new object MyCustomView, and its properties will be unavailable from the controller.
MyCustomView* view = nil;
NSArray *views = [[NSBundle mainBundle] loadNibNamed:#"MyCustomView" owner:self options:nil];
view = views.firstObject;
[self addSubview:view];
Without knowing the setup of the xib, and setting method of the delegate, here is my guess what could help you:
In MyCustomView.xib set the class of the rootView to UIView.
In MyCustomView.xib set the class of the File's Owner to MyCustomView
Create your subview as a UIView.
UIView* view = nil;
NSArray *views = [[NSBundle mainBundle] loadNibNamed:#"MyCustomView" owner:self options:nil];
view = views.firstObject;
[self addSubview:view];
Set the delegate of the myCustomView object in your controller.
self.myCustomView.delegate = self;
I hope it will help, if not, then please extend your question with the delegate setter code block, and your xib setup method. (class of file's owner, class of root view etc)
I created a simple UIView with a UILabel and a UITextField inside of this UIView, this appear fine in the screen but when I touch over the UITextField, the keyboard doesn't appear.
I'm using autolayout programmatic and I'm think the problem is something about UIVIew frame.
I made a simple code to simulate this problem, the most relevant part of code is:
FormInput interface.
//FormInput.h
#import <UIKit/UIKit.h>
#interface FormInput : UIView
#property (nonatomic, strong) NSString *title;
#end
FormInput implementation
// FormInput.m
#import "FormInput.h"
#interface FormInput () <UITextFieldDelegate>
#property (nonatomic, strong) UILabel *label;
#property (nonatomic, strong) UITextField *field;
- (void)setuSubviews;
#end
#implementation FormInput
- (id)init
{
self = [super init];
if(!self) return nil;
[self setuSubviews];
return self;
}
- (void)setuSubviews
{
NSDictionary *views = #{
#"label":self.label,
#"field":self.field
};
[self addSubview:self.label];
[self addSubview:self.field];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[label(<=120)]-2-[field]-0-|" options:0 metrics:nil views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[label]" options:0 metrics:nil views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[field]" options:0 metrics:nil views:views]];
}
#pragma mark - Lazy properties
- (UILabel *)label
{
if(!_label)
{
_label = [UILabel new];
_label.textColor = [UIColor blackColor];
_label.translatesAutoresizingMaskIntoConstraints = NO;
}
return _label;
}
- (UITextField *)field
{
if(!_field)
{
_field = [UITextField new];
_field.translatesAutoresizingMaskIntoConstraints = NO;
_field.font = [UIFont systemFontOfSize:16];
_field.placeholder = #"enter text here";
_field.keyboardType = UIKeyboardTypeDefault;
_field.keyboardAppearance = UIKeyboardAppearanceDark;
_field.returnKeyType = UIReturnKeyDone;
_field.clearButtonMode = UITextFieldViewModeWhileEditing;
_field.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
}
return _field;
}
#pragma mark - Properties setters
- (void)setTitle:(NSString *)title
{
_title = title;
self.label.text = title;
}
#end
View controller
#import "ViewController.h"
#import "FormInput.h"
#interface ViewController ()
#property (nonatomic, strong) FormInput *username;
#property (nonatomic, strong) FormInput *email;
- (void)setupLayout;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// [self setupLayout];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self setupLayout];
}
#pragma mark - Lazy properties
- (FormInput *)username
{
if(!_username)
{
_username = [FormInput new];
_username.translatesAutoresizingMaskIntoConstraints = NO;
_username.title = #"Username:";
}
return _username;
}
- (FormInput *)email
{
if(!_email)
{
_email = [FormInput new];
_email.translatesAutoresizingMaskIntoConstraints = NO;
_email.title = #"Email:";
}
return _email;
}
#pragma mark - Layout setup
- (void)setupLayout
{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.translatesAutoresizingMaskIntoConstraints = NO;
[btn setTitle:#"Button" forState:UIControlStateNormal];
UITextField *field = [UITextField new];
field.translatesAutoresizingMaskIntoConstraints = NO;
field.placeholder = #"Placeholder";
[self.view addSubview:self.username];
[self.view addSubview:self.email];
[self.view addSubview:btn];
[self.view addSubview:field];
NSDictionary *views = #{
#"username" : self.username,
#"email" : self.email,
#"btn" : btn,
#"field" : field
};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[username]-|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[email]-|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[btn]-|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[field]-|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-30-[username]-30-[email]-30-[btn]-30-[field]" options:0 metrics:nil views:views]];
}
#end
Make sure parent containers of the text field in question have "User Interaction Enabled" checked. Maybe you checked it for the text field but not your viewcont?
My reputation is "1" and I can't poste an image, but this check button should be in the interaction part...
Ok I found the reason.
The height of each view in the constraint below still intrinsic:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-30-[username]-30-[email]-30-[btn]-30-[field]" options:0 metrics:nil views:views]]
Thus, just add a vertical height for each view in the constraint visual format below.
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-30-[username(20)]-30-[email(20)]-30-[btn]-30-[field]" options:0 metrics:nil views:views]]
Not trivial but this makes the views inside added view to responds touch actions.
Thanks!