I want to make the width of an UIImageView larger through an animation. I have an UIView with and UIImageView made in the story board. What I want to achieve is so that it looks like the view is scaling from left to right, and keeping its original position. I have tried the following code, but what it does is animating the imageview from the top left corner of its parent view and moving and scaling it until it reaches the position and scale it had from the beginning.
[UIView animateWithDuration:4.0f delay:1.0f options:UIViewAnimationCurveEaseOut animations:^{
CGRect currentFrame = self.imageview1.frame;
currentFrame.size.width = 150;
self.imageview1.frame = currentFrame;
}completion:nil];
Any ideas why this behaviour?
A bit late answer, but I solved the problem. It seems that you cannot change the frame of views in code if autolayout is enabled. Instead you need to animate the constraints of the view, which you can set up in the storyboard and then animate like this:
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.bottomViewY.constant = -196;
[self.view layoutIfNeeded];
} completion:nil];
self.bottomViewY is a constraint which is assigned as an IBOulet. You need to call layoutIfNeeded as it will update the constraints.
Related
I am currently trying to make a UIView containing some UILabel animate to a new size. But doing so I am having some trouble understanding what is really happening with my view. I read some other post about it but I am still unclear about what is really going on.
In my button I added something that just double the size of the right constraint :
[superView layoutIfNeeded];
rightConst.constant *= 2;
[UIView animateWithDuration:3
animations:^{
[superView layoutIfNeeded];
} completion:nil];
superView Being the view I wanna animate and rightConst the constraint to the right.
But doing so, the animation starts but it is actually coming from left. I don't understand this part. My goal would be to animate just the right side of the view to show the resize and maybe the bottom part of the view but the top left should be fixed.
Thanks.
As described in this document, if you call [aView layoutSubviews], layout of the subviews of aView is forced but layout of aView itself is NOT forced.
You need to call layoutSubviews of the superview of the view you want to animate. In this case, the superview of the superview of the two labels.
Solution is here
UIView *theView;
// theView is the superview of the superview of the two labels.
theView = superView.superview;
[theView layoutIfNeeded];
rightConst.constant *= 2;
[UIView animateWithDuration:3
animations:^{
[theView layoutIfNeeded];
} completion:nil];
I have a view controller that contains two views. What I need is that after the view controller has been pushed, the view on top (_sidepanelview) moves to the left disappearing of the screen.
Here is what I wrote:
-(void)viewDidAppear:(BOOL)animated{
CGRect newsidepanelviewposition = _sidepanelview.frame;
newsidepanelviewposition.origin.x = -_sidepanelview.frame.size.width;
[UIView animateWithDuration:0.5 delay:1.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
_sidepanelview.frame = newsidepanelviewposition;
} completion:^(BOOL finished) {
NSLog(#"Done!");
}];
}
The problem is that when I run the app, after the view controller been pushed, the view _sidepanelview disappears from the screen and appears again to the center of the screen coming from the right side instead of moving to the left from x=0 to x= -_sidepanelview width disappearing from the screen.
What I'm doing wrong?
Note: I did the app with auto layout unchecked and the animation worked fine, but using it with the auto layout turned on it freaks out!
As your note suggests, Auto Layout is the "culprit".
Your views have constraints that are periodically enforced by the AutoLayout engine. When you alter the frame of a view, the frame changes, but not the view's layout constraints. When the next cycle of layoutSubviews occurs, your views position and size (i.e. frame) will be reset to what the constraints dictate.
If you want to include AutoLayout for that view/viewcontroller, use constraint changes to perform the animation.
The golden rule here is, setFrame is the antithesis of AutoLayout.
Sample code
-(void)viewDidAppear:(BOOL)animated {
_sidePanelLeadingSpace.constant = -_sidepanelview.frame.size.width; // 1
[UIView animateWithDuration:0.5 delay:1.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
[self.view layoutIfNeeded]; // 2
} completion:^(BOOL finished) {
NSLog(#"Done!");
}];
}
Have a reference, _sidePanelLeadingSpace (NSLayoutConstraint), to the leading space constraint of _sidepanelview, for e.g., as an IBOutlet.
Alter the constraint's constant and layout the view by calling layoutIfNeeded in an animation block
I'm using Objective-C. And I want to make the table view move down with animation when I add a search bar above it. This is my code(table here is my table view):
[UIView animateWithDuration:0.3 animations:^{
CGRect frame = self.table.frame;
frame.origin.y = frame.origin.y+30;
self.table.frame = frame;
}];
But it doesn't work. Someone can help me?
Add layoutIfNeeded at the end of animation block. Like that:
[UIView animateWithDuration:0.3 animations:^{
CGRect frame = self.table.frame;
frame.origin.y = frame.origin.y+30;
self.table.frame = frame;
[self.view layoutIfNeeded];
}];
Changing frames like this is not the best way to do it, and its old fashioned. The best way is to get access to one of the autolayout constraints on the view, and change it. For eg - say your tableview has a top constraint that defines the gap between the top of the tableview and the superview - eg 10px. Drag that constraint from IB, into your class. Best way to do this is to highlight the constraint on the left hand side of IB, in the list that contains all your views etc. Drag across to make it a property in your class, just like you do with a button or label. Then at runtime, you change the .constant property of that constraint. For eg. Heres my NSLayoutConstraint property when dragged across into the class :
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *topBuffer;
Then at the point in code where you want the move to happen, you change the constant property, OUTSIDE of the animation call :
self.topBuffer.constant = 50; //<-- or whatever the new value is
Then all you do is call [self.view layoutIfNeeded] in the animation block. By the way - note here Ive used the anim block with springs etc for a bouncey effect too. Also note - layoutIfNeeded is called on the superview of the object you are changing - so self.view here is my main superview that contains the tableview.
[UIView animateWithDuration:0.7f delay:0 usingSpringWithDamping:1.0 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseIn animations:^(void) {[self.view layoutIfNeeded];} completion:nil];
I am trying to animate change UITableView height constraint using
+ transitionWithView:duration:options:animations:completion:. When the options is set, the UITableViewCell contentView's subview UIView also animates. The effect is like below. As you can see the cell underneath the window goes up and the red dot view's bounds animates to the predefined constraint. If I don't set the animation options, it won't be like this. But I need the animation when I change the UITableView height. So how to keep the table view height animation and disable the table view cell contentView's sub view animation? The code is below. The red dot view is a UIView with a red background color. Is there any way to disable UITableViewCell contentView's subview animation?
- (void)changeTableViewHeight {
self.tableViewTopVerticalSpaceConstraint.constant = 0;
[self.tableView setNeedsUpdateConstraints];
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self.topViewHeightConstraint.constant = 50;
[self.topView setNeedsUpdateConstraints];
}];
}
//1. All constraints change must be done
self.hightConstraint.constant = 200;
self.anotherConstraint.constant = 34;
...
...
// 2. Indimate to iOS that this view need update constraints.
// Hey iOS I have modified few constraints. beware of it to layout that changes.
[self.view setNeedsUpdateConstraints];
// 3. I'm done, relayout the view with animation,
If I really changed any constraints to view.
[UIView animateWithDuration:1.5 animations:^{
[self.view layoutIfNeeded];
}];
Hope somebody will save their time
Had a similar problem that I solved with disabling animation for the layer of the view I didn't want animated. In your case ... implement the awakeFromNib method for your UITableViewCell subclass and disable the animations there. In your case something like ...
override func awakeFromNib() {
super.awakeFromNib()
redCircleView.layer.removeAllAnimations()
}
The thing is that UIView.animateWithDuration animates the views' layers and for new table view cells and other views created during or because of this animation, all changes will also be animated.
... EDIT ...
In the meantime I managed to find an even better solution. In the options parameter for the UIView.animateWithDuration use the UIViewAnimationOptionLayoutSubviews (or .LayoutSubviews in Swift) option. This layouts the subviews at animation commit time.
update code
- (void)changeTableViewHeight {
self.tableViewTopVerticalSpaceConstraint.constant = 0;
self.topViewHeightConstraint.constant = 50;
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
[self.topView setNeedsUpdateConstraints];
}];
}
It's kind the weird I'm facing right now, I know that adding constraints in an AutoLayout IB is simple. But I really couldn't figure-out why my simple constraints are not working when I'm resizing (ZoomIn Animation) a UIView.
The View I'm targeting to zoomIn works fine, but the subviews within it is not being positioned well. It seems that the constraints are not working.
From this setup, where in the Yellow Boxes are UIViews and the Green Boxes are UIImageViews.
When I tapped on a Yellow Box, it should zoomIn, as what is shown on the photo below it.
These are the constraints:
This should be the expected resulting upon zoomIn AnimationBut I got no luck, The yellow box zoomIn but the Green Box is let on its old position and did not changed size.
I put a leading, trailing, topSpace, and bottomSpace from Yellow Box to Green Box already.
My code for resizing the yellow box is:
- (void) resizeViewWithZoomInAnimation: (UIView*)view duration:(float)secs option:(UIViewAnimationOptions) option {
//sets the new width and height of deal's view
float newWidth = view.superview.frame.size.width - 20;
float newHeight = view.superview.frame.size.height - 20;
[UIView animateWithDuration:secs delay:0.0 options:option
animations: ^{
switch ([view tag]) {
case 1:
[view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, newWidth, newHeight)];
break;
case 2:
[view setFrame:CGRectMake(CGRectGetMaxX(view.frame),CGRectGetMinY(view.frame), -newWidth , newHeight)];
break;
case 3:
[view setFrame:CGRectMake(CGRectGetMinX(view.frame),CGRectGetMaxY(view.frame), newWidth , -newHeight)];
break;
case 4:
[view setFrame:CGRectMake(CGRectGetMaxX(view.frame),CGRectGetMaxY(view.frame), -newWidth, -newHeight)];
break;
}
}
completion:nil];
}
This should be the expected resulting upon zoomIn Animation:
When trying to animate with Auto Layout, you should not change view's frames directly. Instead, you should animate changes in constraints.
To access constraints from storyboard you can simply create IBOutlets for them.
[containerView layoutIfNeeded]; // complete pending layout operations (optional)
[UIView animateWithDuration:1.0 animations:^{
// Update constraints
self.viewConstraint1.constant = NEW_VALUE;
self.viewConstraint2.constant = NEW_VALUE;
// Animate the changes
[containerView layoutIfNeeded];
}];
Note that you usually want to call layoutIfNeeded on the super view(or higher) of the view you are trying to animate.
I recommend reading more on Auto Layout in Apple's official guide.
A tweak to the above answer, I used from within a UIViewController
[self.view layoutIfNeeded];
[UIView animateWithDuration:.5
animations:^{
myConstraint.constant = 64;
[self.view layoutIfNeeded];
}
completion:^(BOOL finished) {
// whatever
}];
Changes of note: Apple docs recommend using layoutIfNeeded, and calling this both before and within the animation block. This is so that you can be sure the animation stack is cleared before beginning.
Also, you are to call layoutIfNeeded on the parent view of the constraint you will be animating, not on the view who owns the constraint. Thanks to #nkukushkin for the initial answer.
It's also important to have your constraints set up correctly. The 'fix constraints' tool in IB won't necessary set them up in a way that works correctly for animating. For me I had to go through them and think through how I wanted the dependencies to work, which is of course expected but might not be obvious to the beginner (and results in errors).
When you are using constrains, pre-constrains are generated. When you act on position and size, remove constrains while animating the view or do following:
yourView.translatesAutoresizingMaskIntoConstraints = YES;