UIView animated changes with auto layout constraints - ios

Say that I have a project which looks like the following:
There are two UIViews - one called yellowBox and the other called redBox. The auto layout constraints dictate that the yellowBox is 60 points from the top of the superview with 350 points leading and trailing spaces (i.e. to left and right of the view). The redBox has the same leading and trailing space constraints. There is a vertical space constraint between the two boxes of 0 to indicate that the bottom of the yellowBox should always be directly on top of the redBox.
When the user taps the Expand Yellow Box button, I would like the height of the yellowBox to increase and, as a result, the redBox moves down to continue satisfying the vertical space constraint (that the yellowBox is always on top of the redBox). Here is the animation code:
- (IBAction)expandYellowBox:(id)sender {
[UIView animateWithDuration:0.5
animations:^{
CGRect newFrame = self.yellowBox.frame;
newFrame.size.height += 50;
self.yellowBox.frame = newFrame;
}];
}
However, I have been unable to get this working properly. As you can see by the red icon, there is a problem with the constraints at the moment:
which is fair enough, as there's no way for auto layout to know the height of the boxes. However, I don't know how to resolve this issue in such a way that it will allow for the boxes to be resized and moved. For example, if I specify a height constraint on the yellowBox then that will prevent it from being resized. If I set the height constraint to be greater than or equal (to allow the yellowBox height to increase) then I get a different constraint error:
All constraints have been established using Xcode in the storyboard - none have been written in code.
Any help greatly appreciated.
EDIT: As it turns out, the yellowBox is growing when the button is clicked - it's just I couldn't tell because it appears behind the redBox. I only noticed after clicking it around four times and it started appearing out the bottom of the redBox. However, the same question still remains - how to get the redBox to always stick to the bottom of the yellowBox.

Try it as mentioned by shwet-solanki, but add the following line after changing the constraint:
[self.view layoutIfNeeded];
the IBAction would look like:
- (IBAction)expandYellowBox:(id)sender {
[UIView animateWithDuration:0.5
animations:^{
self.yellowBoxHeightConstraint.constant += 50;
[self.view layoutIfNeeded];
}];
}
Where yellowBoxHeightConstraint is the IBOutlet for height constraint of yellowBox.
Hope this helps.

Add Height constraint to both the views
Create an IBOutlet for height constraint of yellowbox
Now instead of changing the height of yellowbox in the button pressed event, rather change the value of the height constraint. i.e suppose your IBOutlet constraint name is yellowBoxHeightConstraint, then yellowBoxHeightConstraint.constant += 50;
Hope this works for you.

//
// WPViewController.h
// AutoLayoutTEst
//
// Created by VASANTH K on 09/01/14.
//
//
#import <UIKit/UIKit.h>
#interface WPViewController : UIViewController
#property (strong, nonatomic) IBOutlet UIButton *button1;
- (IBAction)buttClicked:(id)sender;
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *heightConstrain;
#property (strong, nonatomic) IBOutlet UIButton *button2;
#end
click Event
- (IBAction)buttClicked:(id)sender {
self.heightConstrain.constant=100;
}
here u need to set the heightConstrain for the Yellow button then create reference outlet for that button then update the heightConstrain to update the size of that button it will automatically move your Red button down.
https://github.com/vasanth3008/AutoLayoutHeighDemo
refer my sample demo project

Related

How to use autolayout to allot full frame to topview when bottom view is hidden

I have two UIViews aligned vertically in Main view, there is business logic like if usertype A is logined need to show both views, If usertype B logined need to show top view only and hide that bottom view but topview should get total frame of bottom view aswell, Can anyone please suggest me how can implement with Autolayout ?.
You should define height constraint for your bottom view.
Main idea is to change that constraint for your purpose. Just create outlet for height in your code and set it constant to 0, when you need to hide it (optionally, set hidden property to YES, if you wish)
Storyboard steps:
Add leading, trailing, top and bottom constraints for top view
Add leading, trailing, height and bottom constraints for bottom view
Your constraints should look like:
Last step - drag outlet for height to your view controller in order to get access to change it's constant
Hope this helps
If your deployment target is iOS 9 or later, the easiest way to do this is to put the views in a UIStackView:
I put the two views (plus the toolbar) in a vertical stack view. I constrained each view's leading and trailing edges to the stack view, and constrained the top and bottom views to have equal heights. Then I set the priority of the equal-height constraint to 249 (a fairly low priority). If you don't want equal heights, you can set whatever height constraints you want for when both views are visible. Just set them to a low priority so the stack view can override them when only one view is showing.
Hiding and showing the views is easy, even with animation. It's this simple:
#interface ViewController ()
#property (strong, nonatomic) IBOutlet UIView *topView;
#property (strong, nonatomic) IBOutlet UIView *bottomView;
#end
#implementation ViewController
- (IBAction)hideTop:(id)sender {
[UIView animateWithDuration:0.3 animations:^{
self.topView.hidden = YES;
self.bottomView.hidden = NO;
}];
}
- (IBAction)hideBottom:(id)sender {
[UIView animateWithDuration:0.3 animations:^{
self.bottomView.hidden = YES;
self.topView.hidden = NO;
}];
}
- (IBAction)showAll:(id)sender {
[UIView animateWithDuration:0.3 animations:^{
self.topView.hidden = NO;
self.bottomView.hidden = NO;
}];
}
#end

AutoLayout setting UILabel height to zero

I have a UILabel for item description amongst other views, all laid out using constraints in Interface Builder - you can see all relevant constraints in the image below. The number of lines is also set to 0.
I haven't set the height constraint because I want the UILabel to resize based on the text it contains. Instead, what happens is right after
[self.view layoutIfNeeded];
is called, the height of the UILabel gets set to 0. Even if I don't set other text to the UILabel, it has a default value of Item description set in Interface Builder.
The item title label above is set the same way, but that one doesn't get squashed to 0, so I'm a bit confused.
Anyone had any experience with such behaviour?
I managed to solve it by setting the UILabel's vertical compression resistance priority to 1000 (default 750) in Interface Builder.
Since my views are embedded in another view, and the parent view's bottom is dependent on the bottom of the lowest child view, I only speculate that the UILabel without a height constraint was getting squeezed in the process of laying out the views. Probably playing with priorities of other constraints somewhere down the chain would have yielded the same result, but I wasn't able to do it successfully. The solution above, however, worked, which is good enough in my case.
Hope this helps someone.
Set 3 constraint
1.Leading space to superview
2.Trailing space to superview
3.Top space to superview
then
#property (nonatomic, strong) IBOutlet UILabel *lbl;
- (void) viewDidLoad{
[self.lbl sizeToFit];
}
ctrl drag from the label to itself > select height > set the constant of the height to 0 and change equal (==) to greater than or equeal (>=)
I think you need to set 5 constraints on your label :
Leading space to superview
Trailing space to superview
Vertical space to "Item"
Vertical space to "Name"
Height
Then add an IBOutlet in your controller on the constraint height (let's say labelHeight).
So in your viewDidLoad you will be able to set this constraint value:
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *labelHeight;
- (void) viewDidLoad{
[self.label sizeToFit];
labelHeight.constant = self.label.frame.size.height;
}
AutoLayout in this UIViewController can't satisfy all the constraints you have set, therefore it dismiss those on your UILabel, resulting in a compressed state. You should have a look at the other constraints in your UIViewController, and set the priority of the height contraint to a higher number.

Moving UIButton on Y axis while using Autolayout

I'm working on a project where I'm using Auto Layout / Universal Story board for the app.
I have a UIButton that I'd like to move to a new position on a certain event. But however without affecting the auto layout. So it will look the same on each device.
I've managed to move the button through this code:
int deltaY = 100;
[ans1 removeConstraints:ans1.constraints];
ans1.frame = CGRectMake(ans1.frame.origin.x, ans1.frame.origin.y + deltaY, ans1.frame.size.width, ans1.frame.size.height);
However the button moves back to it's orginal position within a second or so.
Why do you remove the constrains in your Button? instead of removing constrains, you can create an IBOutlet of the Button Y Constrain & then change that Y Constrain value
Select the LayoutConstraint you want to change, then control drag it to your .h file
#property (nonatomic, weak) IBOutlet NSLayoutConstraint *yAxisConstrain;
Change your Constrain value like this,
yAxisConstrain.constant = 0; //What ever the value you want.
[self.view layoutIfNeeded];

iOS: Change constraints in edit mode

I have a table view with a textfield on the left hand side of a cell and on the right hand side there is a label.
The constraints of the label are very fixed, with a fixed width, vertical center of the container and fixed distance to the right edge of the container.
The constraints of the textfield are variable. It has a fixed position to the left side of the container, also vertical center of the container and a fixed distance to the right edge of the container. But since no width is set, the width is actually variable, depending on the device my app is used.
Now, in edit mode I hide the label and only show the textfield. So I would like to decrease the spacing of the textfield to the right end of the container since no label is in the way. But how can I do this in code? All constraints are set in XCode and I have no experience in doing this with code...
Edit: Screenshot
If I understand your question correctly, you could setup an IBOutlet from your right (Trailing) constraint to your UITableViewCell. Then, in your UITableViewCell, change the constant of the right (Trailing) constraint.
Ex.
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *textFieldTrailingSpaceToViewConstraint;
[self layoutIfNeeded];
[UIView animateWithDuration:0.3f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
{
[textFieldTrailingSpaceToViewConstraint setConstant: 100];
[self layoutIfNeeded];
} completion:nil];

Animating/Moving views under usage of Autolayout

I want to move a view from one postion to another, I can implement it using
self.view.center = CGPointMake(100, 200);
however, if the project is using Autolayout, then the view will be back to original position after running:
[self.view.superview setNeedsLayout];
then how to actually move a view to new position?
With AutoLayout enabled, we should FORGET FRAMES and only CONSIDER CONSTRAINTS.Yes, for animating also you can no longer change the frame or center, view's will revert back to their original position when layout is called.
Instead you should consider changing the constant value of the constraint to get the same effect.
Consider a User Interface like the image given below.I have a image view with a 20 points leading space from it's superview that means it has a horizontal space constraint with it's superview.Also I have three more constraints attached to that image view, top, width and height.
I will show you how we can animate the image from left to right as shown in the image.
Create IBOutlet's for the constraint's we need to animate.Here we are taking only horizontal space constraint, that is enough to move this view from the left to right.
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *horizontalSpaceConstraint;
Inside Go Away action, we need to update the constant value of this constraint.
- (IBAction)moveFrontAction:(id)sender {
self.horizontalSpaceConstraint.constant = 220;
[UIView animateWithDuration:0.5 animations:^{
[self.imageView layoutIfNeeded];
}];
}
Now the view should be moved to the right end.I'm just doing that inside a animation block so we will be able to see a nice animation from left to right and vice versa.In Production, we should not hard code the values like this.Just doing it here to make the concept clear.
Inside the Come Back action, we are again resetting the constant back to it's original value, so you can see the orange image animating back to the original location.
- (IBAction)moveBackAction:(id)sender {
self.horizontalSpaceConstraint.constant = 20;
[UIView animateWithDuration:0.5 animations:^{
[self.imageView layoutIfNeeded];
}];
}
You must change the constraints if you are using autoLayout. The way that is suggested is to make an outlet in your view controller of the constraint, then you change the constant of the constraint. If you have the time i would definitely recommend going here and watching "Auto Layout by Example" or "Best Practices for Mastering Auto Layout". They helped me out a lot. I guess the point to take away is that with autoLayout, you no longer think in terms of frames. So setting the center just doesnt work with auto layout. It's all about how views are related to each other.

Resources