How come my constraints are not working? iOS - ios

I am just trying to set a width and a height constraint on my imgView. I have the following code:
UIImageView *imgView = [[UIImageView alloc] init];
imgView.center = self.view.center;
imgView.image = [UIImage imageNamed:#"favorites5-highlighted.png"];
imgView.contentMode = UIViewContentModeCenter;
[self.view addSubview:imgView];
// width constraint
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imgView(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(imgView)]];
// height constraint
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[imgView(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(imgView)]];
I end up getting this error: Unable to simultaneously satisfy constraints.
I looked up SO and tried adding:
imgView.translatesAutoresizingMaskIntoConstraints = NO;
and
self.view.translatesAutoresizingMaskIntoConstraints = NO;
EDIT:
I am just trying to set the width and height of the imageView to the desired properties. I first tried using
CGRect rect = CGRectMake(0, 0, 10, 10);
imgView.frame = rect;
but nothing changed

Two issues:
You do want:
imgView.translatesAutoresizingMaskIntoConstraints = NO;
You do not want:
self.view.translatesAutoresizingMaskIntoConstraints = NO;
Your attempt to set center is for naught, as when constraints are applied, this will be lost. Unfortunately, you don't define constraints to define the location of the image view. You might do that with the last two lines of the block below:
UIImageView *imgView = [[UIImageView alloc] init];
//imgView.center = self.view.center; // this does nothing in auto layout
imgView.image = [UIImage imageNamed:#"favorites5-highlighted.png"];
imgView.contentMode = UIViewContentModeCenter;
imgView.translatesAutoresizingMaskIntoConstraints = NO; // add this line
[self.view addSubview:imgView];
NSDictionary *views = NSDictionaryOfVariableBindings(imgView);
// width constraint
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imgView(100)]" options:0 metrics:nil views:views]];
// height constraint
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[imgView(100)]" options:0 metrics:nil views:views]];
// center align
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:imgView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:imgView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]];

Related

AutoLayout programmatically doesn't work

I want to go into the depths of auto layout and so I want to do it programmatically in order to understand it properly.I know how to use it through storyboard pretty well.Now here is what I am doing(in viewDidAppear:)
-(void)scenario2{
PGView *viewA = [[PGView alloc]initWithFrame:CGRectMake(100, 100, 100, 100) andBackgroundColor:[UIColor blackColor]];
[self.view addSubview:viewA];
PGView *viewB = [[PGView alloc]initWithFrame:CGRectMake(200, 300, 100, 100) andBackgroundColor:[UIColor yellowColor]];
[self.view addSubview:viewB];
viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewB.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *constraint;
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
//problem statement
constraint = [NSLayoutConstraint constraintWithItem:viewA attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:viewB attribute:NSLayoutAttributeWidth multiplier: 3.0f constant: 0.0f];
[self.view addConstraint:constraint];
NSLog(#"%#",viewA);
NSLog(#"%#",viewB);
}
So here I have initialized two views with different colors.
I know I need to set the property. translatesAutoresizingMaskIntoConstraints to NO before applying any new constraints. So I have done that.
Now I am specifying heights and widths of both the views.So,the x_position and y_position for both the views are 0.I run the code and I get the expected result. Both views have the specified height and width at point (0,0).
Problem
Now when I am writing the statement "problem statement" to adjust the width of viewB according to the width of viewA,its not working.
Also, when I print views viewA and viewB,it prints the frames as (0,0,0,0).
Can anyone explain me this behavior?
Edit:Here are some modifications that I have made.I have checked the ambiguity of both the views using 'hasAmbiguousLayout' and its working fine now.Now what should be the next step if I want to resize viewB's width thrice to that of viewA's width?
-(void)scenario2{
PGView *viewA = [PGView new];
viewA.backgroundColor = [UIColor yellowColor];
[self.view addSubview:viewA];
PGView *viewB = [PGView new];
viewB.backgroundColor = [UIColor blackColor];
[self.view addSubview:viewB];
viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewB.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *constraint;
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
NSLog(#"%d",viewA.hasAmbiguousLayout);
NSLog(#"%d",viewB.hasAmbiguousLayout);
NSLog(#"%#",viewA);
NSLog(#"%#",viewB);
}
The problem is that you've explicitly set width constraints for A and B to be 200 and 100, respectively. So the additional constraint that specifies that one should have a width of three times the other one is unsatisfiable when combined with the other constraints.
Furthermore, the constraints are ambiguous, as you've defined width and height constraints, but haven't defined where the two frames should be. Yes, you've defined the frame for these two views, but that is ignored when you apply the constraints. You probably shouldn't define the frame values at all, as it's misleading and confusing. But you should set, for example, the leading and top constraints, or specify those in the VFL, or add centerX and centerY constraints. You just want some constraints to dictate where the views should be placed and there's lots of ways to specify that.
And the reason that you're not seeing reasonable frame values at the end is that you've defined the constraints, but they haven't been applied yet. You could examine them in viewDidLayoutSubviews, if you wanted.
You might do something like:
- (void)scenario2 {
PGView *viewA = [PGView new];
viewA.backgroundColor = [UIColor yellowColor];
[self.view addSubview:viewA];
PGView *viewB = [PGView new];
viewB.backgroundColor = [UIColor blackColor];
[self.view addSubview:viewB];
viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewB.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *views = NSDictionaryOfVariableBindings(viewA, viewB);
// note, I added `|-100-` to say it's 100 points from the top (and 100 tall)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-100-[viewB(==100)]" options:0 metrics:nil views:views]];
// likewise, to say 200 points from the left (and 100 wide)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-200-[viewB(==100)]" options:0 metrics:nil views:views]];
// again, 100 from the top (as well as 200 tall)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-100-[viewA(==200)]" options:0 metrics:nil views:views]];
// and 100 from the left
// but I've removed width definition, as we'll use your multiplier constraint below
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-100-[viewA]" options:0 metrics:nil views:views]];
// now that we've removed the width constraint from the above,
// this should now work fine
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:viewA attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:viewB attribute:NSLayoutAttributeWidth multiplier: 3.0f constant: 0.0f];
[self.view addConstraint:constraint];
// no point in doing this, because constraints haven't yet been applied
//
// NSLog(#"%#",viewA);
// NSLog(#"%#",viewB);
}
// if you want to see where they are, you could do that here:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
for (UIView *view in self.view.subviews) {
NSLog(#"%#", view);
}
NSLog(#"-----");
}

iOS layer animation stops abruptly

I am trying to use the animation from this library:
https://github.com/shu223/PulsingHalo
I have a UIScrollView, and within it a UIImageView that has a larger width
UIScrollView *scrollView;
scrollView = [[UIScrollView alloc] init];
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.delegate = self;
self.scrollView = scrollView;
[self.view insertSubview:scrollView belowSubview:self.optionsButton];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
imageView = [[UIImageView alloc] init];
self.mapImageView = imageView;
UIImage* mapImg = [UIImage imageNamed:#"..."];
// Add image (larger than screen size) to the image view.
[imageView setImage: mapImg];
// Set the constraints for the scroll view and the image view.
NSDictionary* viewsDictionary = NSDictionaryOfVariableBindings(scrollView, imageView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[imageView]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[imageView]|" options:0 metrics: 0 views:viewsDictionary]];
After this, I add a bunch of buttons to my scrollview, programmatically. For instance:
UIButton* flagButton = [UIButton new];
[self.scrollView addSubview: flagButton];
flagButton.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint* xc = [NSLayoutConstraint constraintWithItem:flagButton attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.mapImageView attribute:NSLayoutAttributeLeft multiplier:1.f constant:x];
NSLayoutConstraint* yc = [NSLayoutConstraint constraintWithItem:flagButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.mapImageView attribute:NSLayoutAttributeTop multiplier:1.f constant:y];
[self.view addConstraints#[xc, yc]];
Now I want to create my halo for this button. I create a specific view for it, centered around my button. I still haven't quite wrapped my head around positioning, so I don't position it for now.
UIView* haloView = [UIView new];
haloView.backgroundColor = [UIColor clearColor];
NSLayoutConstraint* constraintHeight = [NSLayoutConstraint constraintWithItem:haloView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:flagButton attribute:NSLayoutAttributeHeight multiplier:2.0 constant:0.f];
NSLayoutConstraint* constraintWidth = [NSLayoutConstraint constraintWithItem:haloView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:flagButton attribute:NSLayoutAttributeWidth multiplier:2.0 constant:0.f];
NSLayoutConstraint* constraintCenterX = [NSLayoutConstraint constraintWithItem:haloView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:flagButton attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.f];
NSLayoutConstraint* constraintCenterY = [NSLayoutConstraint constraintWithItem:haloView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:flagButton attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.f];
[self.view insertSubview:haloView belowSubview:flagButton];
haloView.translatesAutoresizingMaskIntoConstraints = NO;
constraintCenterX.active = YES;
constraintCenterY.active = YES;
constraintHeight.active = YES;
constraintWidth.active = YES;
PulsingHaloLayer *halo = [PulsingHaloLayer layer];
[haloView.layer insertSublayer:halo atIndex:0];
halo.radius = 50.0;
halo.haloLayerNumber = 4;
halo.duration = 4.0;
This should normally provide me with the pulsing animation shown in the linked library. And I do get it, somewhat. The behavior is hard to describe, but it appears to start correctly, then abruptly stop when it should loop, then restart again a second later. Basically, it does not seem to loop properly as it should, and I have no idea why.
This is the view hierarchy. The last "UIView" is the one with the Halo layer.
These are the UIView's properties as shown by the debugger.
These are the UIScrollView's properties.
Thank you for your help.

scrollView: how to create a pure auto layout scrollview with paging?

Can someone tell me what I did wrong here...
- pin the UIScrollView to its container view
- pin all subviews onto UIScrollView
After reading the Apple TechNote about it, I tried both hybrid method and pure auto layout method. The hybrid method using NIB works awful with paging, it looks like a big picture in a scrollview, rather than paged.
I then created the pure auto layout version in code, UIScrollView as subview of a UIView. This time the view stuck, and the UIImage is gigantic, like its full size:
//scroll view
if (self.scrollView == nil)
{
self.scrollView = [[UIScrollView alloc] initWithFrame:self.frame];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView setClipsToBounds:NO];
[self.scrollView setPagingEnabled:YES];
[self addSubview: self.scrollView];
[self addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView(300)]|"
options:0 metrics:nil
views:#{#"scrollView":self.scrollView}]];
[self addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollView(300)]|"
options:0 metrics:nil
views:#{#"scrollView":self.scrollView}]];
-(void) createContentView
{
for (int i=0; i<self.pageImages.count; i++) {
UILabel* topLabel = [[UILabel alloc] init];
topLabel.text = [NSString stringWithFormat:#"topLabel %d", i+1];
[topLabel sizeToFit];
[self.topLabelArray insertObject:topLabel atIndex:i];
[self.scrollView addSubview:topLabel];
topLabel.translatesAutoresizingMaskIntoConstraints = NO;
UILabel* bottomLabel = [[UILabel alloc] init];
bottomLabel.text = [NSString stringWithFormat:#"bottomLabel %d", i+1];
[bottomLabel sizeToFit];
[self.bottomLabelArray insertObject:bottomLabel atIndex:i];
[self.scrollView addSubview:bottomLabel];
bottomLabel.translatesAutoresizingMaskIntoConstraints = NO;
UIButton* button = [[UIButton alloc] init];
button.titleLabel.text = [NSString stringWithFormat:#"button %d", i+1];
[button sizeToFit];
[self.buttonArray insertObject:button atIndex:i];
[self.scrollView addSubview:button];
button.translatesAutoresizingMaskIntoConstraints = NO;
UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[self.pageImages objectAtIndex:i]]];
imageView.frame = CGRectMake(0,0,200,200);
imageView.translatesAutoresizingMaskIntoConstraints = NO;
imageView.contentMode = UIViewContentModeScaleAspectFit;
[self.pageViews insertObject:imageView atIndex:i];
[self.scrollView addSubview:imageView];
NSDictionary* viewsDictionary = #{#"topLabel":topLabel,
#"bottomLabel":bottomLabel,
#"button": button,
#"imageView": imageView
};
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(10)-[topLabel]-(10)-[imageView]-(10)-[bottomLabel]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:[button]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
if (i==0)
{
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(10)-[topLabel]"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(10)-[imageView]"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(10)-[bottomLabel]-(10)-[button]"
options:0 metrics:nil
views:viewsDictionary]];
}
else if (i == self.pageImages.count)
{
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:-(10)-[topLabel]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:-(10)-[imageView]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:-(10)-[bottomLabel]-(10)-[button]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
}
else
{
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:[prevTopLabel]-(10)-[topLabel]"
options:0 metrics:nil
views:#{#"prevTopLabel": [self.topLabelArray objectAtIndex: i-1],
#"topLabel": topLabel
}]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:[prevImageView]-(10)-[imageView]"
options:0 metrics:nil
views:#{#"prevImageView": [self.pageViews objectAtIndex: i-1],
#"imageView": imageView
}]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:[prevButton]-(10)-[bottomLabel]-(10)-[button]"
options:0 metrics:nil
views:#{#"prevButton": [self.buttonArray objectAtIndex: i-1],
#"button":button,
#"bottomLabel": bottomLabel
}]];
}
[self.scrollView addConstraint:[NSLayoutConstraint
constraintWithItem:topLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:imageView
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0.0]];
[self.scrollView addConstraint:[NSLayoutConstraint
constraintWithItem:bottomLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:imageView
attribute:NSLayoutAttributeCenterX
multiplier:0.8
constant:0.0]];
// [self.scrollView addConstraint:[NSLayoutConstraint
//
Ok, there's a few things wrong here:
else if (i == self.pageImages.count)
This clause will never run, as your loop count is set to break when i == self.pageImages.count -1, here for (int i=0; i<self.pageImages.count; i++).
Next
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:-(10)-[topLabel]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:-(10)-[imageView]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:-(10)-[bottomLabel]-(10)-[button]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
These will also produce invalid constraints, specifically #"H:-(10)-[bottomLabel].... is not pinning the furthest left constraint to anything. All visual format strings that connect views need to start or finish with a view. Either a subview ([subview]) or a superview (|). To fix this, you need to keep a reference to the previous pages label in the loop, and add that to the beginning of your VFL string. Something like this
#"H:[prevBottomLabel]-(10)-[bottomLabel]....
prevBottomLabel = bottomLabel;
// Continue loop
Next:
UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[self.pageImages objectAtIndex:i]]];
imageView.frame = CGRectMake(0,0,200,200);
imageView.translatesAutoresizingMaskIntoConstraints = NO;
imageView.contentMode = UIViewContentModeScaleAspectFit;
This will not have the desired effect, as you can't manually set the frame, then switch on autolayout. Currently, the frame value is ignored, and the height and width are set by the intrinsic content size of the image view, which will be the height and width of the image. If you want to set the height and width, you need to do it with constraints, as so:
[imageView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView(200)]"
options:0 metrics:nil
views:viewsDictionary]];
[imageView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:[imageView(200)]"
options:0 metrics:nil
views:viewsDictionary]];
That should give you some pointers, there may be other mistakes in there too but fixing these is a good place to start.

How to do AutoLayout programmatically with Horizontal scrolling?

I'm trying to do Horizontal scrolling on iOS using AutoLayout programmatically. Here's the link to my github I'm trying to add another NewsSection to the next page but I'm not sure how to do it. Here's the code I'm working on.
- (void) setupNewsView
{
UIView *newsView = [[NewsSection alloc] initWithFrame:CGRectZero];
newsView.backgroundColor = [UIColor redColor];
UIView *anotherNewsView = [[NewsSection alloc] initWithFrame:CGRectZero];
anotherNewsView.backgroundColor = [UIColor blueColor];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
newsView.translatesAutoresizingMaskIntoConstraints = NO;
anotherNewsView.translatesAutoresizingMaskIntoConstraints = NO;
self.scrollView.pagingEnabled = YES;
[self.scrollView addSubview:newsView];
[self.scrollView addSubview:anotherNewsView];
NSDictionary *viewsDict = #{ #"newsView": newsView, #"anotherNewsView": anotherNewsView };
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[newsView]|"
options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom
metrics:nil
views:viewsDict]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[newsView]|"
options:0
metrics:nil
views:viewsDict]];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:newsView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeWidth
multiplier:1.0f
constant:0.0f]];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:newsView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeHeight
multiplier:1.0f
constant:0.0f]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[anotherNewsView(200)]|" options:0 metrics:nil views:viewsDict]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[anotherNewsView(100)]|" options:0 metrics:nil views:viewsDict]];
[self.scrollView setContentSize:CGSizeMake(self.scrollView.frame.size.width * 2, self.scrollView.frame.size.height)];
Right now the app looks like this. What I want is user should be able to scroll to the right and see the blue screen. What constraint do I need to add?
The constraints you have set the blue view to fill the scroll view AND to be of a fixed width, which causes a conflict. The |s at either end of the constraint string make anotherNewsView hug the bounds of its superview (scrollView).
Try dropping the final |s from your constraints. Also position anotherNewsView to be left-aligned with newsView rather than scrollView.
These constraints should do the trick:
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[newsView(500)]" options:0 metrics:nil views:viewsDict]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[newsView(500)][anotherNewsView(100)]" options:0 metrics:nil views:viewsDict]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[anotherNewsView(200)]" options:0 metrics:nil views:viewsDict]];

Center views using *only* visual format?

I'm trying to center 2 views with different height vertically.
UILabel *view1 = [[UILabel alloc] init];
view1.backgroundColor = [UIColor redColor];
view1.text = #"view1\nline2";
view1.textAlignment = NSTextAlignmentCenter;
view1.numberOfLines = 0;
UILabel *view2 = [[UILabel alloc] init];
view2.backgroundColor = [UIColor greenColor];
view2.text = #"view2\nline2";
view2.textAlignment = NSTextAlignmentCenter;
view2.numberOfLines = 0;
[self.view addSubview:view1];
[self.view addSubview:view2];
NSDictionary *views = #{#"view1": view1, #"view2" : view2};
[self.view setTranslatesAutoresizingMaskIntoConstraints:NO];
for (UIView *view in views.allValues) {
[view setTranslatesAutoresizingMaskIntoConstraints:NO];
}
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[view1]-[view2(==view1)]-|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(>=20)-[view1(200)]-(>=20)-|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(>=20)-[view2(100)]-(>=20)-|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil views:views]];
This manages to make the centers of both aligned vertically, but they are at the bottom of the superview!
I want to center vertically not only relative to each other, also in the superview.
I added a constraint like this and it works:
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0]];
But I want to know, is this possible to achieve using only with visual format?
Yes, it's possible, but only by adding spacer views. So if you create a couple of views, lets call them spacer1 and spacer2, you can center view1 with this string,
#"V:|[spacer1][view1][spacer2(==spacer1)]|"
This assumes that view1 has a fixed height. I wouldn't recommend doing it this way though, I would just use the code you show at the bottom of your post.
What about calculating the Y in "metrics" ?
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-centerY-[view1(200)]-(>=20)-|"
options:NSLayoutFormatAlignAllCenterY
metrics:#{#"centerY": #(CGRectGetHeight(self.view.frame)/2.0 - 100)}
views:views]];

Resources