I saw some material on the web, but still can\'t quite get to where I want. I need to animate my view downwards, making it\'s height bigger.
Here is my code so far. What
Can't you just change the frame within a UIView animation block. It looks like that CABasicAnimation is not required in this case.
[UIView beginAnimations:@"resize_animation" context:NULL]; // set your duration. a long duration is better to debug // 0.1 is really short to understand what is going wrong [UIView setAnimationDuration:2]; btnHead.frame = newFrame; [UIView commitAnimations];
Animating the frame
property can be problematic, but it should work correctly as long as the transform
is the identity (that is, you haven't changed it). I just tested the following code, and it worked as expected:
[UIView animateWithDuration:.1f animations:^{
CGRect theFrame = myView.frame;
theFrame.size.height += 50.f;
myView.frame = theFrame;
}];
Again, this won't work as expected if you've changed the transform
property at any time. For a more bulletproof version of this animation, you need to animate the bounds
property like you tried to with Core Animation. You still don't need to drop into Core Animation, though.
The important thing to understand here is the relationship between the bounds
and center
properties. All affine transforms (translate, scale or rotate) need a reference point about which to perform the transform. In the case of a UIView
that is the center
point. CALayer
lets you move the reference point around via the anchorPoint
property, but we don't need to worry about that in this case.
The reason the view scales in both directions is that the scaling operation happens around the center
. The easiest thing to to then, is to move the center
y by half the height delta. Like this:
myView.contentMode = UIViewContentModeRedraw;
[UIView animateWithDuration:.4f animations:^{
CGRect theBounds = myView.bounds;
CGPoint theCenter = myView.center;
theBounds.size.height += 50.f;
theCenter.y += 25.f;
myView.bounds = theBounds;
myView.center = theCenter;
}];
The final consideration is forcing the view to redraw when the bounds
changes. For performance reasons, the view will not redraw when you change its bounds
. However, it does redraw when you change the frame
property (yet another quirk of the frame
property). To force a redraw on bounds
change, you need to set the contentMode
like I did in the first line of the previous snippet. You probably want to set it back after the animation finishes, but that's up to you. This is also the reason your Core Animation version only changes the location and not the size. You need this line in your code somewhere before you run the animation:
self.btnHead.layer.needsDisplayOnBoundsChange = YES;
I hope this all makes sense. The frame
, bounds
and center
properties can be a little confusing at first.
clipsToBounds is the solution.
Explanation:
clipToBounds is a property that specifies if subviews should be cropped or not. So if a subview is bigger than its superview it will be cropped if you set "superview.clipToBounds=YES"
. In the case of this post the superview WAS resized but there was no visible difference for the user, because subviews were drawn even if they were outside of the frame.
It's a little bit tricky, because there is no visible link with the animation, but that's why THIS property makes the difference.
btnHead.clipsToBounds=YES
Solved the issue. Not sure exacly why.