I've got a custom UIView to show a tiled image.
- (void)drawRect:(CGRect)rect
{
...
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClipToRect(context,
CGRectMake(0.0, 0.0, rect.size.width, rect.size.height));
CGContextDrawTiledImage(context, imageRect, imageRef);
...
}
Now I am trying to animate the resize of that view.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
// change frame of view
[UIView commitAnimations];
What I would expect is for the tiled area just to grow, leaving the tile sizes constant. What happens instead is that while the area grows the original content of the view is scaled to the new size. At least during the animation. So the at the beginning and the end of the animation all is good. During the animation the tiles are distorted.
Why is CA trying to scale? How can I prevent it from doing so? What did I miss?
If Core Animation had to call back to your code for every animation frame it would never be as fast as it is, and animation of custom properties has been a long requested feature and FAQ for CA on the Mac.
Using
UIViewContentModeRedraw
is on the right track, and is also the best you'll get from CA. The problem is from the UIKit point of view the frame only has two values: the value at the beginning of the transition and the value at the end of the transition, and that's what you're seeing. If you look at the Core Animation architecture documents you'll see how CA has a private representation of all layer properties and their values changing over time. That's where the frame interpolation is happening, and you can't be notified of changes to that as they happen.So the only way is to use an
NSTimer
(orperformSelector:withObject:afterDelay:
) to change the view frame over time, the old fashioned way.As Duncan indicates, Core Animation won't redraw your UIView's layer's content every frame as it is resized. You need to do that yourself using a timer.
The guys at Omni posted a nice example of how to do animations based on your own custom properties that might be applicable to your case. That example, along with an explanation for how it works, can be found here.
If it is not a big animation or performance isn't an issue for the animation duration, you can use a CADisplayLink. It does smooth out the animation of the scaling of a custom UIView drawing UIBezierPaths for instance. Below is a sample code you can adapt for your image.
The ivars of my custom view contains displayLink as a CADisplayLink, and two CGRects: toFrame and fromFrame, as well as duration and startTime.
Note that I haven't tested its performance, but it does work smoothly.
I stumbled upon this question when trying to animate a size change on a UIView with a border. I hope that others who similarly arrive here might benefit from this answer. Originally I was creating a custom UIView subclass and overriding the drawRect method as follows:
This led to scaling problems when combining with animations as others have mentioned. The top and bottom of the border would grow too thick or two thin and appear scaled. This effect is easily noticeable when toggling on Slow Animations.
The solution was to abandon the custom subclass and instead use this approach:
This fixed the issue with scaling a border on a UIView during animations.
I was facing similar problem in a different context, I stumbled upon this thread and found Duncan's suggestion of setting frame in NSTimer. I implemented this code to achieve the same:
I found out that it takes a long time to set the frame and the timer to complete its operation. It probably depends on how deep the view hierarchy is on which you call -setFrame using this approach. And probably this is the reason why the view is first re-sized and then animated to the origin in the sdk. Or perhaps, is there some problem in the timer mechanism in my code due to which the performance has hindered?
It works, but it is very slow, maybe because my view hierarchy is too deep.
You might want to have a look at http://www.nomadplanet.fr/2010/11/animate-calayer-custom-properties-with-coreanimation/