Animating changing values of CGContextFillRect - iphone

Is it possible to smoothly animate a changed width property of CGContextFillRect over say 5 seconds?
CGContextFillRect(context, CGRectMake(x, y, width, height));
I'm trying to write a method for an iphone app that basically takes a time value and animates the change of CGContextFillRect width from the initial value to the final value smoothly. I need steering in the right direction of research.
If not CGContextFillRect then perhaps there is some other rectangle could be animated like a CALayer? hmmm

A CALayer can be animated trivially in this way. If you want a smooth animation of the CGFillRect you'd have to use a timer or a CADisplayLink or some other timed system.
To do this with a CALayer look into CABasicAnimation, you can tell it to do a cumulative animation, repeated however many times you want.

Related

Changing UIVIEW's transformation/rotation/scale WITHOUT animation

I need to change the size of my images according to their distance from the center of the screen. If an image is closer to the middle, it should be given a scale of 1, and the further it is from the center, the nearer it's scale is to zero by some function.
Since the user is panning the screen, I need a way to change the images (UIViews) scale, but since this is not a very classic animation where I know a how to define an animation sequence exactly - mostly because of timing issues (due to system performance, I don't know how long the animation will last), I am going to need to simply change the scale in one step (no timed animations).
This way every frame the functiion gets called when panning, all images should update easily.
Is there a way to do that ?
You could directly apply a CGAffineTransform to your UIImageView. i,e:
CGAffineTransform trans = CGAffineTransformMakeScale(1.0,1.0);
imageView.transform = trans;
Of course you can change your values, and or use other CGAffineTransform's, this should get you on your way though.
Hope it helps !

CGAffineTransformMakeRotation scales the image

I'm implementing a basic speedometer using an image and rotating it. However, when I set the initial rotation (at something like 240 degrees, converted to radians) It rotates the image and makes it much smaller than it otherwise would be. Some values make the image disappear entirely. (like M_PI_4)
the slider goes from 0-360 for testing.
the following code is called on viewDidLoad, and when the slider value is changed.
-(void) updatePointer
{
double progress = testSlider.value;
progress += pointerStart
CGAffineTransform rotate = CGAffineTransformMakeRotation((progress*M_PI)/180);
[pointerImageView setTransform:rotate];
}
EDIT: Probably important to note that once it gets set the first time, the scale remains the same. So, if I were to set pointerStart to 240, it would shrink, but moving the slider wouldn't change the scale (and it would rotate it as you'd suspect) Replacing "progress" with 240 in the transformation does the same thing. (shrinks it.)
I was able to resolve the issue for anybody who stumbles across this question. Apparently the image is not fully loaded/measured when viewDidLoad is called, so the matrix transforms that cgAffineTransform does actually altered the size of the image. Moving the update code to viewDidAppear fixed the problem.
Take the transform state of the view which you want to rotate and then apply the rotation transform to it.
CGAffineTransform trans = pointerImageView.transform;
pointerImageView.transform = CGAffineTransformRotate(trans, 240);

iOS - Animating text size change in UILabel or UITextView?

In an application showing chunks of text, I'm having the font size increase when the device is turned to a landscape orientation. I don't like how it does the whole animation and then suddenly jumps to the new size, so I'd like to animate the size change over the course of the rotation.
I read somewhere that throwing this change in a UIView animation block doesn't work because the font property is not animatable, so what are my options for doing this?
For my specific implementation I'm not simply scaling the UILabel/UITextView as-is; The bounds of the box is increasing more (proportionally) than the font-size, so there will be re-flow in the text. That's fine by me.
Edit: I would be fine with simply scaling the UITextView.
Also, I was considering "animating" it manually: I have a method that lays out my views and adjusts for font size. If I knew when the rotation was about to start, and the duration of the animation, I could time it so it renders an intermediate font size or two in the middle of the animation. Any help with getting those would be appreciated.
One option is to fade the old text out, change the font size, and fade it back in. The font property may not be animatable, but alpha is. Since alpha is a property of UIView, you can treat all your text-bearing views the same way: UILabel, UITextView, etc. It looks good, too.
If I knew when the rotation was about
to start, and the duration of the
animation...
Funny you should mention that. Just before the animation starts, your view controller will receive a willAnimateRotationToInterfaceOrientation:duration: message that gives you the exact information you need.
A way to proceed could be to:
Create a CAKeyframeAnimation
Define the scaling and rotation you want to achieve during that animation using a set of CATransform3D objects
Add these transforms to your keyframed animation
Send the addAnimation message to your label layer object: [[label layer] addAnimation];
Here would be a code sample assuming yourLabel is the UILabel you want to scale and rotate:
CAKeyframeAnimation *scale = [CAKeyframeAnimation animationWithKeyPath:#"transform"];
CATransform3D scaleUp = CATransform3DMakeScale(1.5, 1.5, 1); // Scale in x and y
CATransform3D rotationScaled = CATransform3DRotate (scaleUp, 90, 0, 0, 1); // Rotate the scaled font
[scale setValues:[NSArray arrayWithObjects:
[NSValue valueWithCATransform3D:CATransform3DIdentity],
[NSValue valueWithCATransform3D:rotationScaled],
nil]];
// set the duration
[scale setDuration: 1.0];
// animate your label layer
[[yourLabel layer] addAnimation:scale forKey:#"scaleText"];
This is typically how a text bouncing around would be animated for instance.
You could start this when the device starts rotating and retrieve the animation when it's done rotating so you can update your label with the proper scale/position.
You will need tuning to find the proper timing and rotation.
Change the font size when didAnimateFirstHalfOfRotationToInterfaceOrientation: is called.
That way the user won't see the change once the rotation completed. It would be pretty hard to see the font size change then, as the rotation is happening!

Can I animate a radial gradient in iPhone?

I would like to animate a radial gradient to shrink and grow the inner radius, as if it were pulsing.
Right now I'm rendering the gradient with CGGradient, but I'm not sure how to animate it. I've seen this topic
Can you animate gradients using Quartz in an iPhone?
Which explains how animate a linear gradient with CAGradientLayer, but it doesn't seem like this will draw a radial gradient.
Is there an easy way to animate a CGGradient, or some way to create a radial gradient CAGradientLayer?
Any thoughts are appreciated.
If only Core Image was on the phone, this would be trivial. An animatable filter is what you need. ;-)
The CAGradientLayer does allow for animating its properties, however, it currently only supports linear gradients.
The only thing I can think of if you're wanting to animate using Core Animation is to animate the transform of the view into which you're drawing your gradient.
You can animate any view's transform pretty simply. Just draw your gradient in the view as you're probably already doing and then animate the transform using scaling. Using explicit animation, it would be something like:
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"transform"];
[anim setFromValue:[NSValue valueWithCATransform3D:CATransform3DIdentity]];
// Scale x and y up
[anim setToValue:[NSValue valueWithCATransform3D:
CATransform3DMakeScale (1.0f, 1.0f,0.0f)]];
[anim setAutoreverses:YES];
[anim setRepeatCount:HUGE_VALF];
[[gradientView layer] addAnimation:anim];
Unfortunately this would look like expanding and contracting more than pulsing, I think (though I haven't tried it).
I think if you want a true pulsing with your gradient at this point, you probably have to do the animation manually using your own timer. Just re-draw periodically changing your inner radius value as you go. Ugh. I'm not absolutely sure that's the only way, but I have yet to see a compelling pulse animation on the phone with a gradient as you're wanting.
There is one other idea I would like to try at some point. Core Animation now allows animating arbitrary properties/values. You could theoretically set up an animation using some arbitrary keypath that you name (say innerRadius, for example) and override the -drawLayerInContext delegate method. Then you could grab the current value from the presentationLayer while it's in mid-flight and re-draw your gradient there instead. This is just theoretical as I haven't tried it, but it seems like it might be worth looking into.
Best regards.

Create a porthole animation transition on the iPhone?

Can anyone recommend how I might be able to create a view transition that looks like a circle expanding from the center of the view?
Any pointers would be helpful, or maybe a link to some similar code, even in a different language.
If you want to do that for images.. then you could use a mask and then make it bigger
Here is how you do it for images
CGRect bounds = CGRectMake(0.0f, 0.0f, 100, 100);
// Create a new path
CGContextRef context = UIGraphicsGetCurrentContext();
CGMutablePathRef path = CGPathCreateMutable();
// Add circle to path
CGPathAddEllipseInRect(path, NULL, bounds);
CGContextAddPath(context, path);
// Clip to the circle and draw the image
CGContextClip(context);
[image drawInRect:bounds]; //HOW WOULD YOU CLIP A VIEW INSTEAD OF AN IMAGE?
CFRelease(path);
Perhaps fill the screen with black, and then remove the black using a EllipseInRect that starts at the center point of the animation, and slowly increases in size and then deletes another segment, which loops until it's completed or hits an upper limit.
The smoothness of the animation would be controlled by how much the size of the Rect (which the Ellipse is then created inside of) increases every x amount of time.
The speed of the animation would be controlled by how often you increase the size of the rect.
Check out CoreGraphics if you haven't already. It's pretty powerful.