Auto Layout: view height is always zero - ios

I have code something like this in viewDidLoad:
UIView *parentView = [[UIView alloc] init];
parentView.translatesAutoresizingMaskIntoConstraints = NO;
UIView *topView = nil;
for (int i = 0; i < 3; i++) {
UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.text = self.data[i];
nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
[parentView addSubview:nameLabel];
UIImageView *clockIconView = [[UIImageView alloc] init];
clockIconView.image = [UIImage imageNamed:#"img"];
clockIconView.translatesAutoresizingMaskIntoConstraints = NO;
[parentView addSubview:clockIconView];
UILabel *timeLabel = [[UILabel alloc] init];
timeLabel.text = self.time;
timeLabel.translatesAutoresizingMaskIntoConstraints = NO;
[parentView addSubview:timeLabel];
[parentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[nameLabel(>=150)]-[clockIconView(20)]-1-[timeLabel(39)]-|"
options:NSLayoutFormatAlignAllBaseline
metrics:nil
views:NSDictionaryOfVariableBindings(nameLabel, clockIconView, timeLabel)]];
// First view - add constraint to superview
if (i == 0) {
[parentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[nameLabel(20)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(nameLabel)]];
}
// Add constraint to previous view
if (topView) {
[parentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[topView]-[nameLabel(20)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(nameLabel, topView)]];
}
// Last view - add constraint to superview's bottom
if (i == 2) {
[parentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[nameLabel(20)]-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(nameLabel)]];
}
[parentView layoutIfNeeded];
topView = nameLabel;
}
NSLog(#"%#", parentView);
First, I add horizontal constraints to align labels and an imageView. Then, I create vertical constraints.
However, parentView's frame has negative origin x and height is always 0. Can't figure out why. Any ideas why height is zero?
<UIView: 0x17037b600; frame = (-129 0; 258 0); autoresize = W+H; layer = <CALayer: 0x170036da0>>

Related

UIScrollView not working properly with layout constraints

Im trying to place 20Textfields vertically and adding constraints to them programmatically and here is my code for that.
//For creating 20 textfields
-(void)createTextFields
{
//create textfields using for loop
for (int i=0; i<20; i++) {
[self createNew:i+1];
}
}
-(void)createNew:(int )count
{
UITextField *textField=[[UITextField alloc]init];
textField.translatesAutoresizingMaskIntoConstraints=NO;
textField.placeholder=[NSString stringWithFormat:#"Enter text:%u",count];
textField.font=[textField.font fontWithSize:10];
textField.backgroundColor = [UIColor colorWithHue:0.8 saturation:0.1 brightness:0.9 alpha:1];
[containerView addSubview:textField];
[inputFieldsArr addObject:textField];
//Left and width
[containerView addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"|-[textField]-|"
options:0 metrics:nil
views:NSDictionaryOfVariableBindings(textField)]];
//Top and height
[containerView addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"V:|-count-[textField(30)]"
options:0
metrics:#{#"count":[NSNumber numberWithInt:count*50]}
views:NSDictionaryOfVariableBindings(textField)]];
// return textField;
}
//Adding a containerview to scrollview
-(void)createScroll
{
scrollview = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
scrollview.showsVerticalScrollIndicator=YES;
scrollview.scrollEnabled=YES;
scrollview.userInteractionEnabled=YES;
scrollview.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scrollview];
scrollview.backgroundColor=[UIColor blackColor];
[scrollview setContentSize:CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height)];
UIView *view=self.view;
//Left and width
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"|-[scrollview]-|"
options:0 metrics:nil
views:NSDictionaryOfVariableBindings(scrollview)]];
//Top and height
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"V:|[scrollview]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(scrollview,view)]];
containerView = [[UIView alloc] init];
containerView.backgroundColor = [UIColor yellowColor]; // just so I can see it
containerView.translatesAutoresizingMaskIntoConstraints = NO;
[scrollview addSubview:containerView];
[self addCOnstriantsToContainer:0];
float height=self.view.frame.size.height;
// CGSize fittingSize = [scrollview systemLayoutSizeFittingSize: UILayoutFittingCompressedSize];
//
// NSLog( #"container fitting size: %#", NSStringFromCGSize( fittingSize ));
//Left and width
}
//Adding Constriants to containerview
-(void)addCOnstriantsToContainer:(float)height
{
float width=self.view.frame.size.width;
// NSLog(#"height:%f",containerView.bounds.size.height);
[scrollview addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"|-[containerView(width)]-|"
options:0
metrics:#{#"width":[NSNumber numberWithFloat:width]}
views:NSDictionaryOfVariableBindings(containerView,scrollview)]];
//Top and height
[scrollview addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"V:|-[containerView(==1000)]-|"
options:0
metrics:#{#"height":[NSNumber numberWithFloat:height]}
views:NSDictionaryOfVariableBindings(containerView,scrollview)]];
//constraintsWithVisualFormat:#"V:|-[containerView(1000)]-|"
}
If I use constraintsWithVisualFormat:#"V:|-[containerView(==1000)]-|", it works fine. But I don't want to assign values statically. How can I set them dynamically? I also have tried constraintsWithVisualFormat:#"V:|[containerView(==scrollView)]|". But none of them worked for me.They can't be scrolled beyond the height of the device.
Any ideas to fix this?
Try to add top and height constraints separately for container view, set height same as scrollView's height, and set priority of height constraint to Low Priority.

Vertical scrolling not working UIScrollView programatically

I am not sure what is wrong with my code. I have embedded UIView inside the UIScrollView. There are some controls which have been embedded inside this UIView. I am expecting the scrolling to happen for the UIView but it does not. Eventually I am unable to view all the controls. I am just pasting my code below. Appreciate if somebody points out what I am missing here.
UIView *parentView = [[UIView alloc]init];
[parentView setTranslatesAutoresizingMaskIntoConstraints:NO];
parentView.backgroundColor = [UIColor whiteColor];
[self.view addSubview: parentView];
NSArray *parentViewHConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:[parentView(==mainView)]" options:0 metrics:0 views:#{#"parentView": parentView, #"mainView":self.view}];
NSArray *parentViewVConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-10-[parentView]-10-|" options:0 metrics:0 views:#{#"parentView": parentView}];
[self.view addConstraints:parentViewHConstraints];
[self.view addConstraints:parentViewVConstraints];
self.myScrollView = [[UIScrollView alloc] init];
//CGSize scrollableSize = CGSizeMake(100, 200);
//[self.myScrollView setContentSize:scrollableSize];
[parentView addSubview:self.myScrollView];
self.myScrollView.backgroundColor = [UIColor lightGrayColor];
self.myScrollView.translatesAutoresizingMaskIntoConstraints = NO;
NSArray *scrollViewHContraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView]|" options:0 metrics:0 views:#{#"scrollView": self.myScrollView}];
[parentView addConstraints:scrollViewHContraints];
UIView *contentView = [[UIView alloc]init];
contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.myScrollView addSubview:contentView];
self.myScrollView.showsVerticalScrollIndicator = YES;
self.myScrollView.pagingEnabled = YES;
self.myScrollView.contentSize = CGSizeMake(510,221);
NSArray *contentViewHConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[contentview(==scrollView)]|" options:0 metrics:nil views:#{#"contentview": contentView,#"scrollView": self.myScrollView}];
NSArray *contentViewVConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[contentview(==scrollView)]|" options:0 metrics:nil views:#{#"contentview": contentView,#"scrollView": self.myScrollView}];
[self.myScrollView addConstraints:contentViewHConstraints];
[self.myScrollView addConstraints:contentViewVConstraints];
UIFont *headingFont = [UIFont fontWithName:#"Helvetica Neue" size:40];
self.m_ObjTopHeadingLbl = [[UILabel alloc]init];
[self.m_ObjTopHeadingLbl setText:#"Registration"];
self.m_ObjTopHeadingLbl.font = headingFont;
[self.m_ObjTopHeadingLbl setTextColor:[UIColor redColor]];
self.m_ObjTopHeadingLbl.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview:self.m_ObjTopHeadingLbl];
NSArray *topHeadingHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[registView]-|" options:0 metrics:nil views:#{#"registView": self.m_ObjTopHeadingLbl}];
[contentView addConstraints:topHeadingHorzConstraint];
// Name field
self.m_ObjNameField = [[JVFloatLabeledTextField alloc]init];
self.m_ObjNameField.borderStyle = UITextBorderStyleRoundedRect;
self.m_ObjNameField.translatesAutoresizingMaskIntoConstraints = NO;
self.m_ObjNameField.placeholder = [NSString stringWithFormat:#"Enter your short name"];
[contentView addSubview:self.m_ObjNameField];
NSArray *nameFieldHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[nameFieldView]-|" options:0 metrics:nil views:#{#"nameFieldView": self.m_ObjNameField}];
[contentView addConstraints:nameFieldHorzConstraint];
// Info on the name field
UILabel* nameFieldLbl = [[UILabel alloc]init];
[nameFieldLbl setText:#"Will be visible to all on ipomo"];
UIFont *nameFieldLblFont = [UIFont fontWithName:#"Arial-BoldMT" size:13];
[nameFieldLbl setFont:nameFieldLblFont];
[nameFieldLbl setTextColor:[UIColor grayColor]];
nameFieldLbl.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview:nameFieldLbl];
NSArray *nameFieldlblHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[nameFieldLbl]-|" options:0 metrics:nil views:#{#"nameFieldLbl": nameFieldLbl}];
[contentView addConstraints:nameFieldlblHorzConstraint];
// Mobilenumber field
self.m_ObjMobNo = [[JVFloatLabeledTextField alloc]init];
self.m_ObjMobNo.borderStyle = UITextBorderStyleRoundedRect;
self.m_ObjMobNo.translatesAutoresizingMaskIntoConstraints = NO;
self.m_ObjMobNo.placeholder = [NSString stringWithFormat:#"Enter your mobilenumber"];
[contentView addSubview:self.m_ObjMobNo];
NSArray *mobnoFieldHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[mobnoField]-|" options:0 metrics:nil views:#{#"mobnoField": self.m_ObjMobNo}];
[contentView addConstraints:mobnoFieldHorzConstraint];
// Info on the mobile number field
UILabel* mobnoFieldLbl = [[UILabel alloc]init];
[mobnoFieldLbl setText:#"To send you the activation code. Hidden and secure"];
dispatch_async(dispatch_get_main_queue(), ^{
mobnoFieldLbl.preferredMaxLayoutWidth = self.view.bounds.size.width;
});
UIFont *mobnoFieldLblFont = [UIFont fontWithName:#"Arial-BoldMT" size:13];
[mobnoFieldLbl setFont:mobnoFieldLblFont];
mobnoFieldLbl.numberOfLines = 0;
[mobnoFieldLbl setTextColor:[UIColor grayColor]];
mobnoFieldLbl.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview:mobnoFieldLbl];
NSArray *mobnoFieldlblHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[mobnoFieldlbl]-|" options:0 metrics:nil views:#{#"mobnoFieldlbl": mobnoFieldLbl}];
[contentView addConstraints:mobnoFieldlblHorzConstraint];
// Email id field
self.m_ObjEmailId = [[JVFloatLabeledTextField alloc]init];
self.m_ObjEmailId.borderStyle = UITextBorderStyleRoundedRect;
self.m_ObjEmailId.translatesAutoresizingMaskIntoConstraints = NO;
self.m_ObjEmailId.placeholder = [NSString stringWithFormat:#"Enter your email id"];
[contentView addSubview:self.m_ObjEmailId];
NSArray *emailFieldHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[emailField]-|" options:0 metrics:nil views:#{#"emailField": self.m_ObjEmailId}];
[contentView addConstraints:emailFieldHorzConstraint];
// Info on the email field
UILabel* emailFieldLbl = [[UILabel alloc]init];
[emailFieldLbl setText:#"To send analytics and reports on happenings in you room(s). Hidden and secure"];
emailFieldLbl.numberOfLines = 0;
UIFont *emailFieldLblFont = [UIFont fontWithName:#"Arial-BoldMT" size:13];
dispatch_async(dispatch_get_main_queue(), ^{
emailFieldLbl.preferredMaxLayoutWidth = self.view.bounds.size.width;
});
[emailFieldLbl setFont:emailFieldLblFont];
[emailFieldLbl setTextColor:[UIColor grayColor]];
emailFieldLbl.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview:emailFieldLbl];
NSArray *emailFieldlblHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[emailFieldlbl]-|" options:0 metrics:nil views:#{#"emailFieldlbl": emailFieldLbl}];
[contentView addConstraints:emailFieldlblHorzConstraint];
// Promo code field
self.m_ObjPromoCode = [[JVFloatLabeledTextField alloc]init];
self.m_ObjPromoCode.borderStyle = UITextBorderStyleRoundedRect;
self.m_ObjPromoCode.translatesAutoresizingMaskIntoConstraints = NO;
self.m_ObjPromoCode.placeholder = [NSString stringWithFormat:#"Enter promocode (if applicable)"];
[contentView addSubview:self.m_ObjPromoCode];
NSArray *promocodeFieldHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[promocodeField]-|" options:0 metrics:nil views:#{#"promocodeField": self.m_ObjPromoCode}];
[contentView addConstraints:promocodeFieldHorzConstraint];
// Submit button
self.m_ObjSubmitBut = [[UIButton alloc]init];
[self.m_ObjSubmitBut setTitle: [NSString stringWithFormat:#"SUBMIT"] forState:UIControlStateNormal];
self.m_ObjSubmitBut.backgroundColor = [UIColor redColor];
[self.m_ObjSubmitBut setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
self.m_ObjSubmitBut.translatesAutoresizingMaskIntoConstraints = NO;
self.m_ObjSubmitBut.layer.cornerRadius = 10;
self.m_ObjSubmitBut.clipsToBounds = YES;
[parentView addSubview:self.m_ObjSubmitBut];
NSDictionary *myTopViews = #{
#"scrollView": self.myScrollView,
#"submitButton": self.m_ObjSubmitBut,
};
NSArray *myTopVConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollView]-[submitButton(40)]|" options:0 metrics:nil views:myTopViews];
NSArray *myTopHConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[submitButton]-|" options:0 metrics:nil views:#{#"submitButton": self.m_ObjSubmitBut}];
[parentView addConstraints:myTopVConstraints];
[parentView addConstraints:myTopHConstraints];
NSDictionary* myViews = #{
#"registView": self.m_ObjTopHeadingLbl,
#"nameView": self.m_ObjNameField,
#"nameFieldLbl": nameFieldLbl,
#"mobnoView":self.m_ObjMobNo,
#"mobnoFieldLbl":mobnoFieldLbl,
#"emailView":self.m_ObjEmailId,
#"emailFieldLbl":emailFieldLbl,
#"promocodeView":self.m_ObjPromoCode
};
NSDictionary* myMetrics = #{
#"sepHeight" : #30.0f,
#"sepHeight1" : #5.0f
};
NSArray *otherConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[registView]-sepHeight-[nameView]-sepHeight1-[nameFieldLbl]-sepHeight-[mobnoView]-sepHeight1-[mobnoFieldLbl]-sepHeight-[emailView]-sepHeight1-[emailFieldLbl]-sepHeight-[promocodeView]" options:0 metrics:myMetrics views:myViews];
[contentView addConstraints:otherConstraints];
You're setting the size of your contentview to be equal to the size of the containing scrollview. Logically this means the scrollview has no area to scroll to and therefore will be fixed. You need to make the contentview longer (for vertical scrolling) or wider (for horizontal scrolling).
I think you are missing to mention scrollEnabled of UIScrollView, try following line and hope it works for you.
scrollView.scrollEnabled = YES;
Also set contentSize and its size should be greater than size of containing window to allow it to be scrollable.
[self.scrollforImage setContentSize:CGSizeMake(3000, 3000)];// replace 3000, 3000 according to your need
The constraints for the scrollview in your code are not sufficient. When using auto-layout, ensure that a proper chain of constraints are added in the vertical and horizontal directions.
For a scroll view to scroll, these are some general guidelines,
Ensure all the different sections of the UI have sufficient number of vertical and horizontal constraints. Take a simple UILabel in the screen. It needs a x,y position - can be a leading/top, centre attribute and it needs a size definition - either fixed width and height or a constraint with the nearby elements. It needs the position - size combination clearly defined for it to be managed by auto-layout.
If you set the translatesAutoresizingMaskIntoConstraints to NO, what you are saying is that the component shouldn't take the frame,size already set to be constraint requirements. If you want to explicitly mention frame or size for some elements, leave this as YES.
If the contentview is pinned in all four sides to the scrollview and the scrollview has its size,position defined as constraints or frame, it will be enough to make the content scrollable.
If the content size of the contentview changes dynamically during different events, you can set the scrollview.contentsize to the contentview.width and contentview.height explicitly.
Also, check this, a technical note from Apple on AutoLayout and Scrollviews.

Adding programatically created views into scrollview vertically (Linear layout in iOS)

I want to add programatically created UIViews into scrollView with auto layout constraints. Like vertical linear layout in Android.
(In objective c not swift)
I have scrollview inside view controller in storyboard. So basically i want to create and add several views in vertical layout with no spaces into that scrollview. And i want to set container size of the scroll view dynamically according to the view heights.
Each view has label inside and each view needs to set its height dynamically according to text size. But probably i need to come to that later.
for (int i=0; i<10; i++)
{
UIView *viewOne = UIView.new;
[viewOne setTranslatesAutoresizingMaskIntoConstraints:NO];
viewOne.backgroundColor = [UIColor redColor];
NSDictionary *viewsDictionary = #{#"viewOne" : viewOne};
NSDictionary *metricsDictionary = #{#"horizontalSpacing" : #10};
[self.scrollview addSubview:viewOne];
NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-horizontalSpacing-[viewOne]-horizontalSpacing-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:metricsDictionary
views:viewsDictionary];
NSArray *const_Height = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[viewOne(50)]"
options:0
metrics:nil
views:viewsDictionary];
[viewOne addConstraints:const_Height];
[self.scrollview addConstraints:horizontalConstraints];
}
With that code i can add views but i need to add one under the other.
In case of using AutoLayout in the context of a UIScrollView I would recommend using a ContentView insider your UIScrollView. Just add them to the ViewControllers View inside the viewDidLoad function.
#interface YourViewController ()
#property (nonatomic, strong) UIScrollView *dataScrollView;
#property (nonatomic, strong) UIView* contentView;
#end
#implementation YourViewController
#synthesize dataScrollView, contentView;
- (void) viewDidLoad {
[super viewDidLoad];
dataScrollView = [[UIScrollView alloc] init];
contentView = [[UIView alloc] init];
// adding the Views programmatically to the hierarchy
[self.view addSubview:dataScrollView];
[dataScrollView addSubview:contentView];
// don't translate the AutoresizingMask into constraints
dataScrollView.translatesAutoresizingMaskIntoConstraints = NO;
contentView.translatesAutoresizingMaskIntoConstraints = NO;
// backgroundColor as you wish?
dataScrollView.backgroundColor = [UIColor clearColor];
contentView.backgroundColor = [UIColor clearColor];
[dataScrollView setScrollEnabled:YES];
[dataScrollView setAlwaysBounceVertical:YES];
NSDictionary* viewsDictionary = NSDictionaryOfVariableBindings(dataScrollView, contentView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[dataScrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[dataScrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[dataScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[contentView(==dataScrollView)]|" options:0 metrics: 0 views:viewsDictionary]];
[dataScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[contentView]|" options:0 metrics: 0 views:viewsDictionary]];
// see below
// [self setUpViews];
}
This Code will do the Trick for one single view. Add your required Views as Subview to the contentView and set the Constraints.
- (void) setUpViews {
UILabel* testLabel = [[UILabel alloc] init];
[testLabel setText:#"Lorem Ipsum"];
testLabel.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview: testLabel];
// clean up your code with this metrics Dictionary
NSDictionary *metrics = #{#"margintop": #40,
#"marginleft": #10,
#"marginright": #10,
#"marginbottom": #20}
// the Views we want to layout with Constraints
NSDictionary *viewsDictionary = #{
#"contentView":contentView,
#"dataScrollView":dataScrollView,
#"testLabel": testLabel}
// Horizontal (testlabel)
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-marginleft-[testLabel]-marginright-|" options:0 metrics: metrics views:viewsDictionary]];
// Vertical
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-margintop-[testLabel]-marginbottom-|" options:0 metrics: metrics views:viewsDictionary]];
}
Referring to your question of adding multiple Views in a for-loop, there are a lot of possible ways. This could be the easiest solution with constraintsWithVisualFormat.
- (void) setUpViews {
NSDictionary *metrics = #{#"margintop": #40,
#"marginleft": #10,
#"marginright": #10,
#"marginbottom": #20,
};
// Alsways like to have contentView and DataScrollView here
NSMutableDictionary* dictViews = [[NSMutableDictionary alloc] initWithDictionary:#{#"contentView":contentView,
#"dataScrollView":dataScrollView}];
// Basic Leading-String for Vertical Constraints
NSString* verticalConstraintsString = #"V:|-margintop-";
for (NSUInteger index = 0; index < 10; index++) {
// Do your Magic here & add your View
UILabel* testLabel = [[UILabel alloc] init];
[testLabel setText:#"Lorem Ipsum"];
testLabel.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview: testLabel];
// Add to global Mutable Views-Dictionary dictViews
[dictViews setObject:testLabel forKey:[NSString stringWithFormat:#"testLabel%lu", (unsigned long)index]];
// add "[testlabel1]" to the vertical Constraints
verticalConstraintsString = [NSString stringWithFormat:#"%#[testLabel%lu]-", verticalConstraintsString, (unsigned long)index];
// Add Horizontal Constraints
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-marginleft-[testLabel%lu]-marginright-|", (unsigned long)index] options:0 metrics: metrics views:#{#"testLabel-%lu":testLabel}]];
}
// Trailing-String
verticalConstraintsString = [NSString stringWithFormat:#"%#marginbottom-|", verticalConstraintsString];
NSDictionary *viewsDictionary = [[NSDictionary alloc] initWithDictionary:dictViews];
// finally adding the vertical Constraints
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalConstraintsString options:0 metrics: metrics views:viewsDictionary]];
}
I hope this will help you to get your Views right.

scrollView doesn't work even though contentSize is larger than frame and subview is added before setting content size

- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.translucent = YES;
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"sprites_0001_Rectangle-1.png"] forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.translucent = YES;
UIImageView *imageView = [[UIImageView alloc]init];
UIImage *image = [UIImage imageNamed:#"sprites_0000s_0008_1st-Page.png"];
imageView.image = image;
//imageView.translatesAutoresizingMaskIntoConstraints = NO;
imageView.backgroundColor = [UIColor clearColor];
self.view = imageView;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
//Write the code to set up view for iPad
}else{
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.backgroundColor = [UIColor clearColor];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scrollView];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-40-[scrollView(==240)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(scrollView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-50-[scrollView(==468)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(scrollView)]];
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"ParentsMock.png"]];
imageView.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:imageView];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[imageView(==1000)]|"
options:0
metrics:0
views:NSDictionaryOfVariableBindings(imageView)]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[imageView(==2000)]|"
options:0
metrics:0
views:NSDictionaryOfVariableBindings(imageView)]];
}
This is my attempt to create UIScrollView programmatically however I couldn't make the scrollView work even though I set the contentSize after adding the subview into the scrollView.
As you can see in this picture, I use UINavigationController to wrap a UIViewControllar and set UIImageView as its view. the I created a scrollView and add it on top of the view. then I create another imageView1 and insert it into the scrollView.
please note that the view of the entire view controller is an imageView which is different from the imageView i insert into the scrollView.
You should set your content size using constraints, ton by setting it directly. It does not scroll because you don't have constraints to the left, top, right or bottom of your scroll view content. See my answer here
Edit:
Try adding this:
imageView.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
#"|[imageView(==1000)]|"
options:0
metrics:0
views:NSDictionaryOfVariableBindings(imageView)]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
#"V:|[imageView(==2000)]|"
options:0
metrics:0
views:NSDictionaryOfVariableBindings(imageView)]];
and remove the code where you are setting the content size.
Edit:
Replace your entire code with this:
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.backgroundColor = [UIColor clearColor];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scrollView];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-40-[scrollView(==240)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(scrollView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-50-[scrollView(==468)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(scrollView)]];
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"ParentsMock.png"]];
imageView.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:imageView];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[imageView(==1000)]|"
options:0
metrics:0
views:NSDictionaryOfVariableBindings(imageView)]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[imageView(==2000)]|"
options:0
metrics:0
views:NSDictionaryOfVariableBindings(imageView)]];
The only way I have been successful in creating UIScrollViews is to use Autolayout. This is the simplest and most effective way I know. For this you will need to remove the
initWithFrame:CGRectMake(40, 100, 240, 168)];
Replace:
NSDictionary *layoutDic = ....
With:
NSDictionary *layoutDic = NSDictionaryOfVariableBindings(scrollView);
Edit: I use your code, and it works, I can scroll, I do in viewDidLoad
UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(40, 100, 240, 168)];
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"purple_button.png"]];
[scrollView addSubview:imageView];
scrollView.contentSize = CGSizeMake(1000, 2000);
scrollView.backgroundColor = [UIColor clearColor];
scrollView.scrollEnabled = YES;
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *layoutDic = NSDictionaryOfVariableBindings(scrollView);
[self.view addSubview:scrollView];
NSArray *scrollViewConstraintWidth = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-40-[scrollView(==240)]" options:0 metrics:nil views:layoutDic];
NSArray *scrollViewConstraintHeight = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-50-[scrollView(==468)]" options:0 metrics:nil views:layoutDic];
[self.view addConstraints:scrollViewConstraintHeight];
[self.view addConstraints:scrollViewConstraintWidth];
in properties under Show the file inspector uncheck Use Auto Layout
Add the delegate to self like this:
UIScrollView *scrollView = [[UIScrollView alloc]init];
scrollView.delegate=self;
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"ParentsMock.png"]];
[scrollView addSubview:imageView];
I found out the answer. It seems that I need to enable userInteraction on UIImageView. Remember when I use UIImageView as the view of the view controller. Therefore default value for userInteractionEnabled Property of UIImageView is NO. It ACCEPTS NO touches at all. We need we enable it like this
imageView.userInteractionEnabled = YES;
PROBLEM Solved.

Align two uiviews below each other using autoloayout

I am trying desperately to align two views below each other with autolayout hoping to animate them in the future and with a relative position this makes it more rigid than just setting frames and updating etc...
So the code:
// create two views
UIView *one = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
UIView *two = [[UIView alloc] initWithFrame:CGRectMake(0, 150, 50, 50)];
// add some color
[one setBackgroundColor:[UIColor whiteColor]];
[two setBackgroundColor:[UIColor redColor]];
// add them to self ( self = uiview )
[self addSubview:one];
[self addSubview:two];
// make dict
NSDictionary *views = NSDictionaryOfVariableBindings(one, two);
// add constraints to make the views as wide as the container ( self )
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[one]|"
options:0
metrics:nil
views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[two]|"
options:0
metrics:nil
views:views]];
// add constraint to make the second ( two ) item 10px below the first ( one )
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[one]-10-[two]"
options:0
metrics:nil
views:views]];
```
<-- the result
<-- the goal
What am i doing wrong?
Thanks in advance!
These two lines explain it all:
UIView *one = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
UIView *two = [[UIView alloc] initWithFrame:CGRectMake(0, 150, 50, 50)];
This is exactly what you are seeing as a result: both views are 50x50 in size, and view two is placed at x=0 and y=150.
When working with autolayout, you need to forget everything about frames and rects. State what constraints you want, for each view and between views, and let autolayout create the frames behind the scenes.
Declare views for autolayout like this:
UIView *one = [[UIView alloc] init];
one.translatesAutoresizingMaskIntoConstraints = NO;
UIView *two = [[UIView alloc] init];
two.translatesAutoresizingMaskIntoConstraints = NO;
You should not set frames while using constraints. That's what constraints are for. Constraints are the cause, frame is the effect
// create two views
UIView *one = [[UIView alloc] init];
UIView *two = [[UIView alloc] init];
one.translatesAutoresizingMaskIntoConstraints = NO;
two.translatesAutoresizingMaskIntoConstraints = NO;
// add some color
[one setBackgroundColor:[UIColor whiteColor]];
[two setBackgroundColor:[UIColor redColor]];
// add them to self ( self = uiview )
[self addSubview:one];
[self addSubview:two];
// make dict
NSDictionary *views = NSDictionaryOfVariableBindings(one, two);
// add constraints to make the views as wide as the container ( self )
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[one]|"
options:0
metrics:nil
views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[two]|"
options:0
metrics:nil
views:views]];
// add constraint to make the second ( two ) item 10px below the first ( one )
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[one]-10-[two]|"
options:0
metrics:nil
views:views]];
Note: I have changed a constraint in the last line. Your constraints did not specify the height of view two. It would have given you an "AMBIGUOUS" layout.

Resources