NSLayoutConstraint - I want to create side margins - ios

I have a view that is in a container
In some of the view controllers that I place in this container, i want to have global side margins
but I don't know how to add them to the container.
I mean I don't know how to define the NSLayoutConstraint to do what I want.
I want side margins of 20pts from each side, left and right of the container, in regards to its superview

It should look something like that:
// Get view and bind that
UIView * view = childViewController.view;
NSDictionary *views = NSDictionaryOfVariableBindings(view); // #"view" : view
// add constraint to view with margins - -value- to supertview - | in horizontal axis
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-20.0-[view]-20.0-|" options:0 metrics:metrics views:views]];
// The same for vertical axis
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-20.0-[view]-20.0-|" options:0 metrics:metrics views:views]];
Also, take a look at this tutorial: http://commandshift.co.uk/blog/2013/01/31/visual-format-language-for-autolayout/ . It looks nice.
Good Luck!

You can solve this with a more intuitive code than the official API (of which the visual format is the easiest to grasp, but still not very intuitive IMHO).
If you use a third party category like https://github.com/jrturton/UIView-Autolayout (which I recommend you do), this is solved with as little code as this:
[yourView pinToSuperviewEdges:JRTViewPinLeftEdge|JRTViewPinRightEdge inset:20.0];
UPDATE
Since your comment states that the right edge does not work, you can try setting the edge constraints individually to debug it, like this:
[yourView pinEdge:NSLayoutAttributeLeft toEdge:NSLayoutAttributeLeft ofView:yourSuperView inset:20];
[yourView pinEdge:NSLayoutAttributeRight toEdge:NSLayoutAttributeRight ofView:yourSuperView inset:40];
Change the inset around on the second constraint to see if you get it right. If it suddenly looks right with an inset of 50, you know that the superview is too wide (by 30 pixels in this case).

Related

Layout format option to use for a width or height constraint?

I'm using the visual format language to create width and height constraints in code. Like this:
[myView addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"V:[myView(100)]"
options:NSLayoutFormatAlignmentMask
metrics:nil
views:views]];
But I really don't know what NSLayoutFormatOption I should be using for the options. One is required for the code to work, but NSLayoutAttributeLeft and the similar ones have nothing to do with width. What should I use for the option in this case?
Use 0 if it doesn't make sense to pass any options.
See Apple's examples in their Auto Layout Guide: Created Constraints Programmatically.
For Swift, use can use the the format options:
NSLayoutFormatOptions.allZeros

Using Auto Layout with Dynamic UITextView, UIImageView, and UILabel Heights

I am trying to create a view that contains one image view with 2 labels and text views. The contents of each element will be read in from an SQLite database, so I would like to use Xcode 5's auto layout to change the heights of each UI element and the distance between them based on the content of each to use the screen space as efficiently as possible. I have a few conditions that I am trying to enforce via auto layout in the interface builder, but I am not sure how to implement them:
The distance between a label and the text view directly below it will stay the same
The widths of all elements will stay the same and they will all be centered horizontally
Only heights and y values of the elements' frames will change
If the content heights of the text views exceed the amount of screen height they can be displayed in, the image view's height should be decreased to a minimum value, then the heights of the text views should be decreased
The distance between each element should be equal (excluding distances between associated labels and text views)
I would be able to do all of this programmatically, but I would like to use the auto layout so the view can easily adapt to changes in screen size and to prevent bugs. I have very little experience with auto layout and I am having trouble with the complex specifications I need in this situation. To make what I intend to create clearer, here is a screenshot of the .xib file:
Thanks for the help!
http://www.techotopia.com/index.php/Implementing_iOS_6_Auto_Layout_Constraints_in_Code
please reffer this website,
may be got your solution
Take a look Autolayout Visual Format Language. They talk about this in a few of the auto layout WWDC videos from last year.
This isn't complete, but you will need to define the constraints both vertically and horizontally. This is complete but hopefully gives you a ruff idea to get your started.
// Vertical alignment should be centered
NSArray *constraints = [NSLayoutConstraint
constraintsWithVisualFormat:#"V:|[_imageView]-[_label1]-[_textBlock1]-[label2]-[textBlock2]-|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:viewsDictionary];
// Tell the views/text blocks to take the entire width. The labels will be fine centered on them I think
NSArray *constraints = [NSLayoutConstraint
constraintsWithVisualFormat:#"H:|-[_imageView]-|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:viewsDictionary];
NSArray *constraints = [NSLayoutConstraint
constraintsWithVisualFormat:#"H:|-[_textBlock1]-|"
options:nil
metrics:nil
views:viewsDictionary];
NSArray *constraints = [NSLayoutConstraint
constraintsWithVisualFormat:#"H:|-[_textBlock2]-|"
options:nil
metrics:nil
views:viewsDictionary];

Evenly Space UIViews of equal sizes in superview using Auto Layout in iOS 6

I am in a need of having the series of buttons to be evenly placed in superview Horizontally using Auto Layout.
Here, I want to keep the sizes of the subviews same, only the center of the subviews will be placed in such a way that there is equal number of space between them.
Note: I dont want to set the Size of the superview, I want every thing to be Auto Layout-ed.
Please Help,
I am stuck !!
Thanks!!
You can create as many UIView's as you have buttons, and center the buttons inside the views, the views can be aligned back to back, using this code:
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[view1][view2][view3]|"
options:0
metrics:nil
views:views]];
Make sure you first remove existing constraints from the superview using:
[self.view removeConstraints:self.view.constraints];
and in the viewDidLoad turn off auto resizing conversion:
[self.view setTranslatesAutoresizingMaskIntoConstraints:NO];

How Does Scrollview Work With Autolayout, and Why Does Setting the Bottom Vertical Space Constraint Make it Work?

I'm trying to understand how UIScrollView works in an auto layout environment. So far I've tried reading the Apple documentation, Stack Overflow research, Google research, and studying Matt Neuberg's working example.
The Apple 6.1 documentation says:
The central notion of a UIScrollView object (or, simply, a scroll
view) is that it is a view whose origin is adjustable over the content
view. It clips the content to its frame, which generally (but not
necessarily) coincides with that of the application’s main window. A
scroll view tracks the movements of fingers and adjusts the origin
accordingly. The view that is showing its content “through” the scroll
view draws that portion of itself based on the new origin, which is
pinned to an offset in the content view. The scroll view itself does
no drawing except for displaying vertical and horizontal scroll
indicators. The scroll view must know the size of the content view so
it knows when to stop scrolling; by default, it “bounces” back when
scrolling exceeds the bounds of the content.
Based on this, let's walk through how constraints ought to be set up.
To make it easier to discuss, lets say we have 3 views as a general case - the default main view controller view (A), its subview being a UIScrollview (B), and the UIScrollview has a single subview which is a UIView (C). Let's say we want (C) to be 1000 units tall.
So we go into the interface builder, select the view controller in the story board and on the attributes inspector tab change the size to freeform. For views (A), (B), and (C) we change the height to 1000 on the size inspector tab.
Constraints Between (A) and Main Window
Time to setup constraints. The documentation clearly states "(The Scrollview) clips the content to its frame, which generally (...) coincides with that of the application’s main window". In our example (A) will coincide with the application main window and no constraints are necessary for this.
Constraints Between (A) and (B)
Now the documentation was clear about having (B) coincide exactly with (A), so we'll set up 4 constraints between them, leading space, trailing space, top space, and bottom space to superview all with a constant of 0.
Constraints Between (B) and (C)
The documentation is not so straight forward here. It says that (B)'s origin is adjustable over (C), so (B) should definitely be smaller than (C). Since we know the scrolling is only going to be up and down, we can constrain the left and right edged between (B) and (C) to zero, and we always want it to be in the middle so we'll add a center x alignment. We'll add 3 constraints between them, leading space and trailing space to superview with a constant of 0, and center x alignment. In order to position the view we need something for the top and bottom, and honestly I'm not sure how these constraints should be set up based on the documentation. Based on imitating Matt Neuberg's example I made them top space to superview with a constant of zero, and bottom space to superview with whatever constant it generates by default. This bottom space to superview constraint is special (apparently), from now on it shall be referred to as "specialConstraint".
So... what?! We started this paragraph out by saying (B) should definitely be smaller than (C), and ended it by setting up constraints to make them exactly the same size. Question 1 - Why is this?
Constraints on (C) by Itself
We know that (C) must be larger than (B) so that (B) has something to scroll over, and (C) should determine its size based on its own constraints. Easy enough, we set 1 constraint, height = 1000.
specialConstraint
Now we create an outlet for specialConstraint in the view controller, and in the viewDidLoad method we set self.specialConstraint.constant = 0; This means that the bottom of the content view should be pinned exactly to the bottom of the scroll view, which would give you nothing to scroll down over. But this works in Matt Neuberg's example. Question 2 - why is this?
What's Really Happening When a Scrollview Scrolls
I would think the logical thing to do would be to have the frame of the scroll view fixed, and the origin of the content view (or the content offset) move around with the scrolling and the content shows the scrollview like a window. Similar to viewing a paper through a hole in a wall by sliding the paper around.
However, based on my reading the scrollview's frame is actually doing the moving, like a magnifying glass over a fixed page.
Question 3 - Can someone please explain what's happening when a scrollview scrolls, which object's frame origin is actually changing, and why is it done this way?
Question 4 - Can anyone explain how the constraints should be set between (A), (B), and (C) in plain English?
Working example
Hi. At first, here is working code scroll view example writed couple of days ago.
[self addSubview:scrollView];
id views = NSDictionaryOfVariableBindings(scrollView);
[self addConstraints:PVVFL(#"H:|[scrollView]|").withViews(views).asArray];
[self addConstraints:PVVFL(#"V:|[scrollView]|").withViews(views).asArray];
Constraints writed in code and with help of Parus lib.
As you can mention, scroll view is tied to it's superview. In another words, it fill it completely.
Couple of lines earlier i setup an scrollView tree.
id views = NSDictionaryOfVariableBindings(photoView, storeNameLabel, selectStoreButton, tagsLabel, tagsContainer, editTagsButton, commentView, sendButton, cancelButton);
[scrollView addConstraints:PVVFL(#"V:|-15-[photoView(150)]").withViews(views).asArray];
[scrollView addConstraints:PVVFL(#"|-15-[photoView]-15-|").withViews(views).asArray];
[scrollView addConstraint:PVCenterXOf(photoView).equalTo.centerXOf(scrollView).asConstraint];
[scrollView addConstraint:PVTopOf(storeNameLabel).equalTo.bottomOf(photoView).plus(20).asConstraint];
[scrollView addConstraints:
PVVFL(#"|-15-[storeNameLabel]-(>=15)-[selectStoreButton]-15-|")
.alignAllBaseline.withViews(views).asArray];
[selectStoreButton setContentCompressionResistancePriority:UILayoutPriorityRequired
forAxis:UILayoutConstraintAxisHorizontal];
[scrollView addConstraints:
PVVFL(#"V:[storeNameLabel]-15-[tagsLabel][tagsContainer]").alignAllLeft.withViews(views).asArray];
[scrollView addConstraint:PVRightOf(tagsContainer).equalTo.rightOf(selectStoreButton).asConstraint];
[scrollView addConstraint:PVTopOf(editTagsButton).equalTo.bottomOf(tagsContainer).plus(10).asConstraint];
[scrollView addConstraint:PVWidthOf(editTagsButton).equalTo.widthOf(tagsContainer).asConstraint];
[scrollView addConstraint:PVLeftOf(editTagsButton).equalTo.leftOf(tagsContainer).asConstraint];
[scrollView addConstraint:PVTopOf(commentView).equalTo.bottomOf(editTagsButton).plus(10).asConstraint];
[scrollView addConstraint:PVWidthOf(commentView).equalTo.widthOf(editTagsButton).asConstraint];
[scrollView addConstraint:PVLeftOf(commentView).equalTo.leftOf(editTagsButton).asConstraint];
[scrollView addConstraint:PVHeightOf(commentView).moreThan.constant(100).asConstraint];
[scrollView addConstraint:PVLeftOf(cancelButton).equalTo.leftOf(commentView).asConstraint];
[scrollView addConstraints:PVVFL(#"[cancelButton]-(>=15)-[sendButton(==cancelButton)]").alignAllBaseline.withViews(views).asArray];
[scrollView addConstraint:PVRightOf(sendButton).equalTo.rightOf(commentView).asConstraint];
[scrollView addConstraints:PVVFL(#"V:[commentView]-10-[cancelButton]-10-|").withViews(views).asArray];
How you can see, this is pretty complicated layout.
But key points of it: Internal views have fixed heights, provided by theirs intrinsic content sizes. Combined all together they tried to increase height of scrollView.
But scrollView height is fixed by self.view!!! Constraint solver must generate error. But,
Theory
Apple has special Tech note for this case. And there is some interesting moment:
To make this work with Auto Layout, the top, left, bottom, and right edges within a scroll view now mean the edges of its content view.
Also this note provide some examples of different approaches when working with scroll views and auto-layouts.
Now i will try to answer your questions.
Answers
Question 1 - Why is this?
As you can read above, this is because auto-layout for scroll view setup content view sizes and not frame sizes.
Question 2 - why is this?
Again, thing is in content size. Special constraint approach looks like hack over interface builder. At xib you have normal size view, and after nib-file instantiating you just back things to normal, fixing this constraint to 0, which mean that content size of scroll view will be equal to C view.
Question 3 - Can someone please explain what's happening when a scrollview scrolls, which object's frame origin is actually changing, and why is it done this way?
Great explanation of this process you can find at this article: Understanding Scroll Views, but short answer is: UIScroll view perform scrolling by changing self.bounds.origin point.
Question 4 - Can anyone explain how the constraints should be set between (A), (B), and (C) in plain English?
You should set constraints inside the scroll view by fixing all edges to internal view. In another words, all edges of scroll view must be fixed twice: By internal views and by superview.
If answer on this question are not clear yet, you can read this answer from very beginning.
I found a lot of examples how to do it but not one explaining how to set the contensize at Runtime. So with a button.
Actually it all boils down to having a relation between your scrollviews content and the scrollView.
Now you can make a scrollview scroll and resize without code just in storyboard. Only you have to do it right.
To adjust the contensize with a button (at runtime) you need to adjust the constraints of your content.
This is difficult to understand. I have put the code on github http://goo.gl/qrXANp and you can find video about it here ... https://www.youtube.com/watch?v=4oCWxHLBQ-A
Basic trick to solve this mystery issue is .. Embedded another view
inside scrollview and set constraints like below
UIView --> UIScrollView -->ContentView
and you can keep on add subview to contentView at runtime and uiscrollview content size will increase automatically
self.ContentView = [[UIView alloc] initWithFrame:CGRectZero];
self.ContentView.translatesAutoresizingMaskIntoConstraints = NO;
self.scrollview = [[UIScrollView alloc] initWithFrame:CGRectZero];
self.scrollview.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollview sizeToFit];
[self.scrollview addSubview:self.ContentView];
[self.view addSubview:self.scrollview];
NSMutableDictionary *views = [[NSMutableDictionary alloc] init];
[views setValue:self.ContentView forKey:#"ContentView"];
[views setValue:self.scrollview forKey:#"scrollview"];
[views setValue:self.view forKey:#"mainView"];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[scrollview]-0-|"
options:0
metrics:nil
views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[scrollview]-0-|"
options:0
metrics:nil
views:views]];
[self.scrollview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[ContentView]|"
options:0
metrics:nil
views:views]];
[self.scrollview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[ContentView]|"
options:0
metrics:nil
views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[ContentView(==mainView)]"
options:0
metrics:nil
views:views]];
self.view.contentMode = UIViewContentModeRedraw;
[self.view setNeedsUpdateConstraints];

iOS: Simple AutoLayout with 1 Label and 3 Buttons

I'm playing around with AutoLayout and am really banging my head against the wall for what seems like it ought to be an extremely simple solution.
I've got a vertical column of controls: 1 label and 3 buttons.
I want the label to be 40 pixels(points) tall and auto-size its width based on the width of its superview (standard spacing on left, top and right).
I want the 3 buttons to line up vertically below that label.
I would like their widths to auto-size just like the label.
I would like their spacing to be standard (aqua?) spacing (8 points, right?).
I would like the 3 buttons to be the same height.
I can get what I want to happen to work, but I keep getting errors in the console at runtime, and I'd like to figure out WHY I'm getting them and HOW to avoid getting them. I've watched the WWDC videos on AutoLayout, and here's what I've tried so far:
UILabel *label = [self Label];
MMGlossyButton *button1 = ...
MMGlossyButton *button2 = ...
MMGlossyButton *button3 = ...
[[self view] addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[label]-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(label)]];
[[self view] addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[button1]-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(new)]];
[[self view] addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[button2]-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(existing)]];
[[self view] addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[button3]-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(provider)]];
[[self view] addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[label(40)]-[button1(>=25)]-[button2(==button1)]-[button3(==button1)]-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(label, button1, button2, button3)]];
So, this works for displaying the view in a dynamically-sized way, but the following error pops up in the console:
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you
don't understand, refer to the documentation for the UIView
property translatesAutoresizingMaskIntoConstraints)
// A whole bunch of constraint stuff that doesn't appear to be important...
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7554c40 V:[MMGlossyButton:0x7554b40(99)]>
So, the last bit appears to indicate that the first button I have on the view is statically sized to 99 points tall.
Which is the size it has on the view.
Which is completely arbitrary.
Which I don't want assigned, but can't figure out a way to un-assign it.
Although I'm getting what I want (sort of, eventually), it seems to be a REALLY roundabout way to accomplish something that's pretty simple. Am I missing something basic about AutoLayout, or does its power require such complexity?
You are encountering errors because you are mixing and matching constraints generated in code with constraints added by interface builder. Interface builder doesn't let you generate an ambiguous layout, so almost by definition if you add additional constraints, you will get an "Unable to simultaneously satisfy" error, which is the downfall of many a marriage.
To resolve this you either need to define all the constraints you need in interface builder, or you need to mark specific ones as outlets and remove them in code before adding your own.
In your case, the constraints are simple enough to create in IB.
You can pin to a specific height by using this button in IB while your label is selected:
The one in the middle, that looks like a girder. This gives you the following useful menu:
Choosing one of these allows you to create a new constraint against the label, which you can then edit by selecting it:
You can then add your buttons, select all three of them and, using the same menu, create an equal heights constraint.
The constraints created in IB aren't particularly flexible, so if you do decide you need to create or modify them in code, it is best to create outlets to the particular constraints, and then either remove and re-create them, or modify the constant value at run time.

Resources