I have created a UIScrollView in code and it works in iOS10. I updated my Xcode today and it is no longer scrolling in iOS11 (simulator is iOS11 and does not work; physical iPad is still iOS10 and works).
User can add subviews when they want. When its the first subview, I anchor it to the left side, top and bottom of the scroll view. Then I anchor the right side of the subview to the right side of the scroll view which gives the contentSize its size and so it knows it needs to enable scrolling
UIScrollView *scrollViewMain = [UIScrollView new];
scrollViewMain.delegate = self;
scrollViewMain.backgroundColor = [UIColor greenColor];
scrollViewMain.translatesAutoresizingMaskIntoConstraints = NO;
scrollViewMain.directionalLockEnabled = YES;
self.scrollViewMain = scrollViewMain;
... // other code
if (self.countPlayers == 1) {
[self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[playerCardView(400)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];
[self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-20-[playerCardView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.scrollViewMain attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:playerCardView attribute:NSLayoutAttributeRight multiplier:1 constant:10];
self.constraintScrollViewRight = constraint;
[self.scrollViewMain addConstraint:constraint];
}
else {
[self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[previousPlayerCardView]-[playerCardView(==previousPlayerCardView)]" options:0 metrics:nil views:#{#"previousPlayerCardView": player.previousPlayer.playerViewCard, #"playerCardView": player.playerViewCard}]];
[self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-20-[playerCardView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];
}
if (self.constraintScrollViewRight) {
[self.scrollViewMain removeConstraint:self.constraintScrollViewRight];
}
NSLayoutConstraint *constraintRight = [NSLayoutConstraint constraintWithItem:self.scrollViewMain attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:playerCardView attribute:NSLayoutAttributeRight multiplier:1 constant:10];
self.constraintScrollViewRight = constraintRight;
[self.scrollViewMain addConstraint:constraintRight];
[self.scrollViewMain layoutIfNeeded];
DLog(#"self.scrollViewMain: %#", self.scrollViewMain);
DLog(#"self.scrollViewMain.contentSize: %#", NSStringFromCGSize(self.scrollViewMain.contentSize));
The contentSize does become larger then the scroll view's frame:
2017-10-04 20:01:58.479446-0500 [ViewController addPlayer]_block_invoke [Line 242] self.scrollViewMain: <UIScrollView: 0x7fa9fd01b000; frame = (286 20; 462 1014); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x60000005ff20>; layer = <CALayer: 0x600000233580>; contentOffset: {0, 0}; contentSize: {826, 89}; adjustedContentInset: {0, 0, 0, 0}>
2017-10-04 20:01:58.479969-0500 [ViewController addPlayer]_block_invoke [Line 243] self.scrollViewMain.contentSize: {826, 89}
Why does iOS11 break my code?
EDIT:
Also, I try to scroll to the right to show the new subview when it appears:
[self.scrollViewMain scrollRectToVisible:playerCardView.frame animated:YES];
And it does nothing.
SOLUTION:
I changed
[self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[playerCardView(200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];
To
[self.scrollViewMain addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollViewMain attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:playerCardView attribute:NSLayoutAttributeLeft multiplier:1 constant:10]];
The UIScrollView now has a left and right anchor and can calculate its contentSize.
Kind of a crappy bug that the Visual Format is partially broken now.
Why does iOS11 break my code?
Because that is Apple's job.
Try creating all your constraints without using NSLayoutConstraint constraintsWithVisualFormat:
I've just had the exact same problem in my app on iOS 11, after upgrading to XCode 9.
After several hours of trying to find out what constraint caused the problems in my code, I happened to replace all calls to NSLayoutConstraint constraintsWithVisualFormat: with building the constraints "by code" using NSLayoutConstraint constraintWithItem: instead; and now it works as it's supposed to...
I guess Apple has modified the visual format analyzer in a way that causes some unexpected side effects...
Related
I am trying to add a button to a UIstackview, programmatically. All this is in fitxero XIB.
The button is created correctly, but when adding the constraints I get the following error:
2020-05-21 17:51:08.328369+0200 eWAS[3391:567586] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view?
That's illegal. constraint: < NSLayoutConstraint:0x282362b70 V:|-(0)-[UIButton:0x11c225a60'button'] (active, names: '|':UIStackView:0x11bfc13f0 ) > view:< UIButton: 0x11c225a60; frame = (0 0; 30 150); opaque = NO; layer = < CALayer: 0x2802e4220 > >'
-(void) configureTabsWithTexts: (NSArray *) tabs{
NSInteger tag = 0;
UIButton *currentButton = [UIButton buttonWithType:UIButtonTypeSystem];
[currentButton setTitle:#"Button1" forState:UIControlStateNormal];
[currentButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[currentButton setTag:tag];
[currentButton.titleLabel setFont:[UIFont systemFontOfSize:20]];
[currentButton.titleLabel setTextColor:[UIColor whiteColor]];
[currentButton setFrame:CGRectMake(0, 0, 30, 150)];
currentButton.backgroundColor = [UIColor blackColor];
[self.stackViewForButtons addSubview:currentButton];
[currentButton setTranslatesAutoresizingMaskIntoConstraints:NO];
NSMutableArray <NSLayoutConstraint *> *arrayConstraints = [[NSMutableArray alloc] init];
currentButton.translatesAutoresizingMaskIntoConstraints = false;
[currentButton addSubview:self.stackViewForButtons];
[currentButton addConstraint: [NSLayoutConstraint constraintWithItem:currentButton
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.stackViewForButtons
attribute:NSLayoutAttributeTop
multiplier:1
constant:0]];
[currentButton addConstraint: [NSLayoutConstraint constraintWithItem:currentButton
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:currentButton.superview
attribute:NSLayoutAttributeBottom
multiplier:1
constant:0]];
[currentButton addConstraint: [NSLayoutConstraint constraintWithItem:currentButton
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:50]];
[currentButton addConstraint: [NSLayoutConstraint constraintWithItem:currentButton
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:currentButton.superview
attribute:NSLayoutAttributeLeading
multiplier:1
constant:0]];
}
You have this line:
[self.stackViewForButtons addSubview:currentButton];
which seems fine, but then later you are doing:
[currentButton addSubview:self.stackViewForButtons];
which seems backwards and is probably the source of your problem. Try removing that latter line and see if it works. I doubt you want a UIButton to have a stack view as a subview. With both lines in place, there is a circular reference, which UIView probably figures out and removes the original superview of the UIButton, meaning that is nil when you are creating the later constraints (or maybe it removes the superview/subview relationship altogether).
As an aside, if you are using an actual UIStackView which it looks like you are, you shouldn't need any of these constraints done by hand. The entire point of UIStackView is to generate all those constraints for you. In that case, simply call:
[self.stackViewForButtons addArrangedSubview:currentButton];
[currentButton setTranslatesAutoresizingMaskIntoConstraints:NO];
and you should be done, provided you have configured the stack view correctly. Maybe you need the width constraint on each one, not sure. While you can add non-arranged subviews to a UIStackView, that should be rare. And even if that is intended in this case, you may be better off adding another UIStackView as a subview, then adding the buttons to that.
I am working on a menubar app, that uses NSPopover. I am using the following code to present popover.
[self.mainPopover showRelativeToRect:[testView bounds] ofView:testView preferredEdge:NSMinYEdge];
Issue is this is being present too close to status bar as shown below.
Even if i change the rect it does not have any effect and rightly so, as the documentation states
The rectangle within positioningView relative to which the popover should be positioned. Normally set to the bounds of positioningView. May be an empty rectangle, which will default to the bounds of positioningView.
Following is the screenshot from dropbox app, was just wondering how can i add some spacing in my app like dropbox.
To achieve this i added a padding view and attach set NSStatusItem View to that container view. Code from the solution used is as follow for anybody looking to implement it.
_paddingView = [NSView new];
[_containerView addSubview:_paddingView];
[_containerView addSubview:_dragView];
[_dragView setTranslatesAutoresizingMaskIntoConstraints:NO];
[_paddingView setTranslatesAutoresizingMaskIntoConstraints:NO];
[_containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_dragView(22)][_paddingView(5)]|" options:0
metrics:nil views:views]];
[_containerView addConstraint:[NSLayoutConstraint constraintWithItem:_dragView
attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
toItem:_paddingView attribute:NSLayoutAttributeLeft
multiplier:1. constant:0]];
[_containerView addConstraint:[NSLayoutConstraint constraintWithItem:_dragView
attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
toItem:_paddingView attribute:NSLayoutAttributeRight
multiplier:1. constant:0]];
self.mainPopover = [[NSPopover alloc] init];
self.mainPopover.delegate = self;
self.mainPopover.backgroundColor = [NSColor greenColor];
[self.mainPopover setAnimates:NO];
[self.mainPopover setBehavior:NSPopoverBehaviorTransient];
[self.mainPopover setContentViewController:viewController];
[_containerView layoutSubtreeIfNeeded];
[_statusItem setView:_containerView];
You could inset the test view bounds to add some margin between de view and popover:
NSPopover *mainPopover = [self mainPopover];
NSRect bounds = CGRectInset([testView bounds], -50.0, -50.0);
[mainPopover showRelativeToRect:bounds ofView:testView preferredEdge:NSMinYEdge];
I have a UIView that contains subviews that looks like this:
This view was originally designed with 320 width in mind. iPhone 5s and lower. However I am now adapting it to work with iPhone 6+
The issue I am facing is getting the subviews width to grow to accommodate the extra space on the left and right of their super view. I can only seem to get the centre views width to grow, however not the out views. What constraints would I need to apply or change in order to get all views to grow a little to accommodate the extra space on the sides?
Hi!
If you design your view in interface builder, you may try this:
1- set all views to specific width and height
2- the view at the corner add pin to the edge with static value.
3- the view in the middle add pin to top or bottom, and add align constraint to horizontal centre of superview
Not sure if this help, Just try to answer!
Here is a complete example of how to achieve this programmatically (with dummy views):
// Simple example demonstrating the below screenshots
// Create containers to hold each row of subviews
UIView *container1 = [UIView new];
container1.translatesAutoresizingMaskIntoConstraints = NO;
container1.backgroundColor = [UIColor redColor];
UIView *container2 = [UIView new];
container2.translatesAutoresizingMaskIntoConstraints = NO;
container2.backgroundColor = [UIColor orangeColor];
// Create the subviews
UIView *v1 = [UIView new];
v1.translatesAutoresizingMaskIntoConstraints = NO;
v1.backgroundColor = [UIColor grayColor];
UIView *v2 = [UIView new];
v2.translatesAutoresizingMaskIntoConstraints = NO;
v2.backgroundColor = [UIColor blackColor];
UIView *v3 = [UIView new];
v3.translatesAutoresizingMaskIntoConstraints = NO;
v3.backgroundColor = [UIColor greenColor];
UIView *v4 = [UIView new];
v4.translatesAutoresizingMaskIntoConstraints = NO;
v4.backgroundColor = [UIColor purpleColor];
UIView *v5 = [UIView new];
v5.translatesAutoresizingMaskIntoConstraints = NO;
v5.backgroundColor = [UIColor blueColor];
UIView *v6 = [UIView new];
v6.translatesAutoresizingMaskIntoConstraints = NO;
v6.backgroundColor = [UIColor yellowColor];
// add the subviews
[container1 addSubview:v1];
[container1 addSubview:v2];
[container1 addSubview:v3];
[container2 addSubview:v4];
[container2 addSubview:v5];
[container2 addSubview:v6];
// Add the containers to the root view (in this case self.view)
[self.view addSubview:container1];
[self.view addSubview:container2];
// Add constraints for the containers
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[container1]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(container1)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[container2]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(container2)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-64.0-[container1(==100)]-[container2(==container1)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(container1, container2)]];
// Add constraints in both VFL and regular NSConstraints to the subviews of container 1
[container1 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[v1]-[v2(==v1)]-[v3(==v1)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v1,v2,v3)]];
[container1 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[v1]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v1)]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v2 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v1 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v2 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container1 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v3 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v1 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v3 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container1 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
// Add constraints in both VFL and regular NSConstraints to the subviews of container 2
[container2 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[v4]-[v5(==v4)]-[v6(==v4)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v4,v5,v6)]];
[container2 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[v4]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v4)]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v5 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v4 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v5 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container2 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v6 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v4 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v6 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container2 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
Attached are screenshots on iPhone 5s, iPhone 6 and iPhone 6 Plus respectively:
iPhone 5s
iPhone 6
iPhone 6 Plus
I hope this at least point you in the right direction =)
disable autolayout and use autoresizing masks in the interface builderHandling Layout Changes Automatically Using Autoresizing Rules
When my table view is empty, I want to add a simple label into the tableview footer to display a "no content" message. It was working fine when I was setting the frames of the UILabel and the UIView that I used for footerView, but now I'm trying to convert to using auto-layout, and I can't get it to work.
Here's what I'm doing:
// Create the footer
UIView *tempFooter = [[UIView alloc] init];
UILabel *atext = [[UILabel alloc] init];
tempFooter.translatesAutoresizingMaskIntoConstraints = NO;
atext.translatesAutoresizingMaskIntoConstraints = NO;
atext.numberOfLines = 0;
[atext setText:#"Add Some Text"];
atext.textAlignment = NSTextAlignmentCenter;
atext.font = [UIFont italicSystemFontOfSize:14];
atext.textColor = [UIColor grayColor];
atext.backgroundColor = [UIColor clearColor];
atext.lineBreakMode = NSLineBreakByWordWrapping;
// add label to footer view, and add constraints
[tempFooter addSubview:atext];
NSLayoutConstraint *tvatt1 = [NSLayoutConstraint constraintWithItem:tempFooter
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:atext attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:10.0];
NSLayoutConstraint *tvatt2 = [NSLayoutConstraint constraintWithItem:tempFooter
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:atext
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:10.0];
NSLayoutConstraint *tvatt3 = [NSLayoutConstraint constraintWithItem:tempFooter
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:atext
attribute:NSLayoutAttributeTop
multiplier:5.0
constant:0];
NSLayoutConstraint *tvatt4 = [NSLayoutConstraint constraintWithItem:tempFooter
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:atext
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant: 0];
[tempFooter addConstraints: #[tvatt1, tvatt2, tvatt3, tvatt4]];
// set the footerview
self.tview.tableFooterView = tempFooter;
When I run this, I get a crash:
2014-09-08 19:57:16.594 SimpleList[49442:60b] * Assertion failure in
-[UITableView layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2935.137/UIView.m:8794 2014-09-08
19:57:21.073 SimpleList[49442:60b] * Terminating app due to uncaught
exception 'NSInternalInconsistencyException', reason: 'Auto Layout
still required after executing -layoutSubviews. UITableView's
implementation of -layoutSubviews needs to call super
I'm not sure what I'm doing wrong. I've also tried setting constraints for the self.tview.tableFooterView wrt the tempFooter (pinning against all 4 sides) but that doesn't change the crash. I also call:
[self.tview.tableFooterView layoutSubviews];
but that doesn't help either.
Any ideas what I'm doing wrong?
You shouldn't set translatesAutoresizingMaskIntoConstraints to NO for table views, their cells, or table header and footer views (or for your controller's self.view for that matter). It's ok to use constraints for views inside those views (the content view of cells or the header and footer views). I added a simplified version of your code to viewDidLoad, and it worked as expected. Note that you need to give the footer view a height and an x position (the y position and the width are ignored),
UIView *tempFooter = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 50)];
UILabel *atext = [[UILabel alloc] init];
atext.translatesAutoresizingMaskIntoConstraints = NO;
atext.numberOfLines = 0;
[atext setText:#"Add Some Text"];
atext.textAlignment = NSTextAlignmentCenter;
atext.font = [UIFont italicSystemFontOfSize:14];
atext.textColor = [UIColor grayColor];
atext.backgroundColor = [UIColor clearColor];
atext.lineBreakMode = NSLineBreakByWordWrapping;
[tempFooter addSubview:atext];
NSDictionary *dict = NSDictionaryOfVariableBindings(atext);
[tempFooter addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|-10-[atext]-10-|" options:0 metrics:nil views:dict]];
[tempFooter addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[atext]|" options:0 metrics:nil views:dict]];
self.tableView.tableFooterView = tempFooter;
I'm not sure what you were trying to accomplish with your constraint, tvatt3. The multiplier (you have 5) doesn't do anything with a top or left constraint since the value of those attributes is 0. I used the visual constraints, rather than the method you used, but when I used your code to add the constraints, it worked also .
Interestingly, changing the Autoresizing mask in the xib solved my problem.
Constraints not working:
Working:
I was able to make dynamically auto layout table footer width and height by implementing #rdelmar solution for constraints and adding these lines below. Same solution applies to table header view.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let tableFooter = tableView.tableFooterView {
let maxSize = CGSize(width: self.tableView.bounds.size.width,
height: CGFloat.greatestFiniteMagnitude)
let size = tableFooter.systemLayoutSizeFitting(maxSize)
let height = size.height
var headerFrame = tableFooter.frame
// If we don't have this check, viewDidLayoutSubviews() will get
// repeatedly, causing the app to hang.
if height != headerFrame.size.height {
headerFrame.size.height = height
tableFooter.frame = headerFrame
tableView.tableFooterView = tableFooter
}
}
}
P. S. I prefer Interface Builder for constraints setup
hope this will help you
I am not sure of this but it help me in my project, first add every thing in contentView (all the subview and the constraint)
[self.contentView addSubview:atext]
and then comes to code part
NSLayoutConstraint *tvatt1 = [NSLayoutConstraint constraintWithItem:tempFooter
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:atext attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:10.0];
code saying for left attribute
temfooter(must be equal) = 1.0*atext +10.0
i.e
temfooter must be equal to the modified atext , so need to make sure that your constraints are not wrong.
I have an UIScrollview which will contain X views, each view is of Class type "CategoryPostView" that contains an UIImageView. I am adding these views on the scrollView one after another. But when the image loads in the imageView I want to change the size of my imageView, therefor I want to change the Offset y of my all other views in the scrollView.
I am using autolayout constraint on UIScrollView but I couldn't reach to any result. This is the code I am using:
int categoryScrollY = 0.0;
CategoryPostView *previousView = nil;
for(; self.indexOfCate
goryInTheScroll < [self.categoryItemsArray count]; self.indexOfCategoryInTheScroll++){
PostItem *postItemObj = [self.categoryItemsArray objectAtIndex:self.indexOfCategoryInTheScroll];
CategoryPostView *categoryPostViewObj = [[CategoryPostView alloc] initWithFrame:CGRectMake(0.0, categoryScrollY, 148.0, 76.0)];
categoryPostViewObj.translatesAutoresizingMaskIntoConstraints = NO; //This part hung me up
[categoryPostViewObj setupPostViewWithItem:postItemObj];
[self.categoriesScrollView addSubview:categoryPostViewObj];
categoryScrollY += 80.0;
[_categoriesScrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[categoryPostViewObj]"
options:0 metrics:nil
views:#{#"categoryPostViewObj":categoryPostViewObj}]];
if (!previousView) { // first one, pin to top
[self.categoriesScrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[categoryPostViewObj]"
options:0 metrics:nil
views:#{#"categoryPostViewObj":categoryPostViewObj}]];
}else{
[self.categoriesScrollView addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:#"V:[previousView][categoryPostViewObj]"
options:0 metrics:nil
views:#{#"categoryPostViewObj":categoryPostViewObj, #"previousView":previousView}]];
}
if(self.indexOfCategoryInTheScroll == ([self.categoryItemsArray count] - 1))
{
[self.categoriesScrollView addConstraint:[NSLayoutConstraint constraintWithItem:categoryPostViewObj
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.categoriesScrollView
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0]];
}
previousView = categoryPostViewObj;
}
For now, I have the views on top of each other. I have to somehow apply my constraint from the bottom of the previous view and not from the top of the previous view. I guess I should add options to this line of code:
[self.categoriesScrollView addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:#"V:[previousView][categoryPostViewObj]"
options:0 metrics:nil
views:#{#"categoryPostViewObj":categoryPostViewObj, #"previousView":previousView}]];
Many thanks!
The best way to use constraints inside a UIScrollView is to not use them at all.
If you want to layout the inside of the scroll view using constraints then create a UIView to contain everything in the scroll view and then place this view into the scroll view.
By doing this you can now use the container view that you created to place all the constraints inside.
I ended up using the class UIView+AutoLayout.
You can find it here https://github.com/smileyborg/UIView-AutoLayout and https://github.com/jrturton/UIView-Autolayout