Autolayout issues when adding a new view into a hierarchy - ios

I'm struggling big time with a couple of scenarios when i have a UIView with constraints applied via IB and adding a new UIView into it's view hierarchy. Here's how it goes:
I have a full screen UITableView with the following constraints applied so it scales nicely through all the resolutions of iOS devices:
Now i'd like to add a UIView above the UITableView acting as a sort-of toolbar.
Right now the only possible way i succeeded in adding this view is adding it on top of the TableView, so that it covers the top of tableview. What i'd like to achieve is the newly added UIView pushing table down so both are visible. I tried several things including adding a container view in IB just above the tableview however that didn't work at all.
So my question is: is there a way to dynamically edit, remove and add new constraints to the view hierarchy, ideally supporting animation?

You can create IBOutlets for a constraint, just like any view.
Each NSLayoutConstraint object has a constant property that you can set anytime in code (it's the value of the constraint).
So you would create both views on Interface Builder, and constraint the top of the table view to the bottom of the new view.
The new view will have a set height constraint, and you create an outlet to that height constraint to make that view appear or disappear in code.
There are other possible solutions but I think this one is the easiest.
The code would be something like this:
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *topHeightConstraint;
To set the value:
self.topHeightConstraint.constant = 60;
and to animate it:
[UIView animateWithDuration:0.6 animations:^{
self.topHeightConstraint.constant = 60;
[self.view layoutIfNeeded];
}];

Related

How to remove space of hidden UIImage?

I'm stuck that I don't know how to remove spacing of hidden UIImage. Purpose is If flag is true, UIImage will be displayed and if flag is false, UIImage is hidden but space of this hidden image is still there.
I'm using Auto Layout.
If you are using Auto Layout and Storyboard you can set create an IBOutlet as a property of your Controller class. You then hook that up to the width constraint of the UIImage. In your code when the UIImage is hidden you set the IBConstraint to 0. When it is shown, you set the IBConstraint back to the normal width.
(in Controller.h)
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *constraintImageWidth;
(in Controller.m) (pseudo code)
if(hidden){
constraintImageWidth.constant = 0;
}
else{
constraintImageWidth.constant = 30;
}
There should also be a horizontal constraint between the left side of the label and the right side of the image set up in the Storyboard.
Here is where you would check the width box to add the width constraint.
Here is where you would connect the referencing Outlet to the IBOutlet on your controller
The easiest and most effective way to handle this is using Stack Views.
Insert both the images in a horizontal stack view and stack view will internally take care of the spacing. Additional properties like alignment, spacing can be tweaked as per requirement.
Keep in mind that you will have to re-establish the constraints between stack view and adjacent elements since once the views are added to a stack view all if its constraints are cleared

UITableView Auto-Layout Flexible Height

I have following design.
Am using AutoLayout to make every thing flexible. In this design i have a UIView which is Gray in Color as showing in image and a UITableView below UIView. Some times i have to show this UIView and some times i have to hide this Gray UIView.
My problem is when ever i hide UIView, UITableView is not fixing its height. I don't want to hard code in .m file. Is it possible AutoLayout take care of this issue. I have these constraints as below image. Am i missing any constrain.
When i try to change UIView height, UITableView is not moving up and showing some orange constraints as show in image.
The contraints looks good. All you have to do to show/hide the gray UIView is change the height constraint constant.
To do this, create an IBOutlet in your controller for the constraint (you do this the same way you would for a UIView IBOutlet), and when you want to hide the gray view, set the constant property of the constraint to 0.
eg.
#interface MyViewController
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *greyViewHeightConstraint;
#end
and when you want to hide the view:
self.greyViewHeightConstraint.constant = 0;
To show the view again, you would have to save the "default" constant value after the storyboard is loaded (like in viewDidLoad for example), and set self.greyViewHeightConstraint.constant to this saved value.
Note also that these constraint changes can be animated.
The "orange constraint" you are seeing in Interface Builder is normal: it indicates that the view frame is not matching the constraints you set. You can then update the frame to respect the constraints, or update the constraints to match the frame.

Using Auto layout with hidden views

I have a view controller with a UIScrollView. Inside that scrollview I have two UIViews. viewA sits onto of viewB. I am using Xcode 5 and auto layout in this project. What I would like to do is when viewA is hidden, move viewB to the top where viewA was sitting (technically, still sitting, just hidden).
I looked at this SO answer: How to use auto-layout to move other views when a view is hidden?
However it hasn't really helped me. I connected a IBOutlet which was a constant to the vertical spacing to the top of the scroll view and set it to 0.0f when viewA was hidden. However it makes no changes to my UI at all.
First get the Top Space to SuperView NSlayoutConstraints Outlets for both subViews and then do the following:-
[self.aView setHidden:YES];
if([self.aView isHidden])
{
self.bViewTopConstraint.constant = self.aViewTopConstraint.constant;
}
using this the second UiView will go to the place of first UIView.
For Scrollview you have to set the constraints value properly. No need to set any contentsize. Once you set the constriants scrollview will work automatically.
Check the attached screenshot.

Nested UIScrollViews and AutoLayout

I have seen several similar issues here in StackOverflow regarding UIScrollView and AutoLayout but now is my turn because I can't make it work properly.
My idea is to have an inner UIScrollView that scrolls horizontally (contains a set of images) and an outer UIScrollView that apart from the inner above, contains multiple UILabel, UITextView objects and scrolls vertically.
Without AutoLayout both are acting like expected but unfortunately size and origin are not right. With AutoLayout, outer UIScrollView, scrolls a bit but inner not moving at all. I can confirm that inner UIScrollView has the correct ContentSize during viewDidLoad but later in code has 0,0.
Below is a screenshot with views and associated Constrains.
Any idea?
UPDATE
For others who may face the same problem as mine.
In my case seems that the UIPageControl was messing up the whole thing. As you can see in the screenshot, I had the pager as a subview of the inner UISrollView WRONG!!!
I've simply move out the UIPageControl (became subview of the outer) and left Xcode to do the rest (Editor > Resolve Auto Layout Issues > Add Missing Constrains In View Controller). After that, UIScrollViews took tare of their selves (as Apple states in documentation). I've spent so many hours on this. I hope my solution saves others' time.
I am working on Xcode5
I've solved UIScrollView content issues with 2 steps:
Select UIScrollView, go to Editor>Resolve Auto Layout Issues>Add missing constraints
Add a IBOutlet NSLayoutConstraint for the height of whatever you are going to put inside the UIScrollView e.g. UIWebView. Hook up this outlet to the Height constraint you add via storyboard.
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightConstraint;
//set the constant to the element once it has been drawn
self.heightConstraint.constant = frame.size.height;
Hope this helps.

Animate a view containing subviews with autolayout

This is the setup:
A UIView created on Interface Builder, linked to an IBOutlet variable (_vAbout)
A constraint for this view that we want to animate, linked to an IBOutlet variable (_ctrBottomAboutView)
I am using this code to animate:
_ctrBottomAboutView.constant = -100;
[UIView animateWithDuration:0.5 animations:^{
[_vAbout layoutIfNeeded];
}
My problem is: whenever the view has any subviews in it, the animation doesn't work. However, if the view has no children, the animation works correctly.
Do you have any idea of a solution? I have tried everything: adding and removing constraints instead of modificating the constant value, adding constraints to the subviews on Interface Builder...
After some experiments starting from the ground with an empty project, this is what I've found:
Given A the view we want to animate and B its superview
It's very important to keep in mind that the view that receives the layoutIfNeeded message is the view that owns the constraint.
In the case of NSLayoutAttributeWidth and NSLayoutAttributeHeight the owner of the constraint is actually A, but in all the other cases, the view that owns the constraint is B
HOWEVER
If A does not have any subviews, we can call [A layoutIfNeeded] at any time on our code and it will work
If A has one or more subviews but we start the animation on viewDidLoad we can call [A layoutIfNeeded] and it will work

Resources