iOS: Change constraints in edit mode - ios

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];

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

Programmatically stretch UIButton width depending on condition

I've got two UIButtons into a view, which is 232px wide.
The buttons are aligned such as
|[BUTTON1][BUTTON1]|
|-------232px------|
I have a set of constraints for this alignment, but now I want to be able to change the frame of BUTTON1's to full width, depending on a condition, so it'd have to be programmatically. I tried changing the frame, but since it's automatically updated, it won't work. Basically, what I want to achieve is BUTTON1 covering BUTTON2, Is there an easy way to do this?
As you are using autoLayout in your project, so to change the frame of your button, you have to change the constraint of you UIButton.
First make the IBOutlet of your buttons' width constraint and then when you want to change the frame of the button update that constraint like this
button.widthConstraint.constant = //set the constraint;
[UIView animateWithDuration:0.25f
animations:^{
[self.view setNeedsLayout];
}
completion:^(BOOL finished) {
}];
Make the outlet of button and width constraint and then
self.buttonWidthConstraint += 20 // adjust as per requirements
[self.myButton updateConstraints]
You can set the constant of the button you want covered to 0 and animate the change. Then the covering button will fill in the whole space.

UIView animated changes with auto layout constraints

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

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.

iOS: How does one animate to new autolayout constraint (height)

I've never worked with autolayout constraints before. I have a small new app I'm working on and noticed that the NIB's views are defaulting to autolayout. So, I figured I'd take the opportunity to work with it and try to figure out where Apple is going with this.
First challenge:
I need to resize an MKMapView and I'd like to animate it to the new position. If I do this the way I'm used to:
[UIView animateWithDuration:1.2f
animations:^{
CGRect theFrame = worldView.frame;
CGRect newFrame = CGRectMake(theFrame.origin.x, theFrame.origin.y, theFrame.size.width, theFrame.size.height - 170);
worldView.frame = newFrame;
}];
...then the MKMapView will 'snap' back to its original height whenever a sibling view gets updated (in my case a UISegmentedControl's title is being updated [myUISegmentedControl setTitle:newTitle forSegmentAtIndex:0]).
So, what I think I want to do is change the constraints of the MKMapView from being equal to the parent view's hight to being relative to the top of the UISegmentedControl that it was covering: V:[MKMapView]-(16)-[UISegmentedControl]
What I want is for the MKMapView height to shorten so that some controls beneath the map view are revealed. To do so I think I need to change the constraint from a fixed full size view to one where the bottom is constrained to the top of a UISegmentedControl...and I'd like it to animate as view shrinks to new size.
How does one go about this?
Edit - this animation is not animating though the bottom of the view does move up 170 instantly:
[UIView animateWithDuration:1.2f
animations:^{
self.nibMapViewConstraint.constant = -170;
}];
and the nibMapViewConstraint is wired up in IB to the bottom Vertical Space constraint.
After updating your constraint:
[UIView animateWithDuration:0.5 animations:^{[self.view layoutIfNeeded];}];
Replace self.view with a reference to the containing view.
This works for me (Both iOS7 and iOS8+). Click on the auto layout constraint you would like to adjust (in interface builder e.g top constraint). Next make this an IBOutlet;
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;
Animate upwards;
self.topConstraint.constant = -100;
[self.viewToAnimate setNeedsUpdateConstraints];
[UIView animateWithDuration:1.5 animations:^{
[self.viewToAnimate layoutIfNeeded];
}];
Animate back to original place
self.topConstraint.constant = 0;
[self.viewToAnimate setNeedsUpdateConstraints];
[UIView animateWithDuration:1.5 animations:^{
[self.viewToAnimate layoutIfNeeded];
}];
There is a very good tutorial from apple itself that explain how to use animation with autolayout.
Follow this link and then find the video named "Auto layout by example"
It gives some interesting stuff about autolayout and the last part is about how to use animation.
I have made this small demo available. It shows how auto-layout constraints can be changed and animated in a very simple example. Simply take a look at the DemoViewController.m.
Most people use autolayout to layout items on their views and modify the layout constrains to create animations.
An easy way to do this without a lot of code is creating the UIView you want to animate in Storyboard and then creating a hidden UIView where you want the UIView to end. You can use the preview in xcode to make sure both UIViews are where you want them to be. After that, hide the ending UIView and swap the layout constraints.
There is a podfile for swapping layout constrains called SBP if you don't want to write it yourself.
Here's a tutorial.
No need to use more IBOutlet reference of the constraint instead of this you can directly access or update already applied constraint either applied by Programmatically or from Interface Builder on any view using the KVConstraintExtensionsMaster library. This library is also managing the Cumulative behavior of NSLayoutConstraint.
To add Height Constraint on containerView
CGFloat height = 200;
[self.containerView applyHeightConstrain:height];
To update Height Constraint of containerView with animation
[self.containerView accessAppliedConstraintByAttribute:NSLayoutAttributeHeight completion:^(NSLayoutConstraint *expectedConstraint){
if (expectedConstraint) {
expectedConstraint.constant = 100;
/* for the animation */
[self.containerView updateModifyConstraintsWithAnimation:NULL];
}
}];

Resources