I am attempting to rotate a UIImageView around an anchor point to simulate a "radar sweep" style animation. My understanding of anchor points leads me to believe that (1, 1) should be the bottom right corner of the radar image. However, setting the ImageView's anchor point to this doesn't give me the behavior I anticipated. This can be viewed here.
As can be seen, the anchor point is a ways up the right side of the image, though it is correctly at the center. What I want is the image to rotate around the center point, like a radar sweep.
Here is the relevant code:
self.radarView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, barDimension, barDimension)];
self.radarView.contentMode = UIViewContentModeScaleAspectFill;
self.radarView.image = [UIImage imageNamed:#"radarSweep.png"];
self.radarView.layer.anchorPoint = CGPointMake(1, 1);
self.radarView.layer.position = CGPointMake(screenWidth / 2.0, screenHeight / 2.0);
[self.mapView addSubview:self.radarView];
CABasicAnimation *opacityInAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
[opacityInAnim setFromValue:[NSNumber numberWithFloat:0.0]];
[opacityInAnim setToValue:[NSNumber numberWithFloat:1.0]];
opacityInAnim.duration = 0.25;
opacityInAnim.fillMode = kCAFillModeForwards;
opacityInAnim.removedOnCompletion = NO;
opacityInAnim.beginTime = 0.0;
opacityInAnim.delegate = self;
[opacityInAnim setValue:#"radarSweep" forKey:#"animName"];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
animation.fromValue = [NSNumber numberWithFloat:0.0];
animation.toValue = [NSNumber numberWithFloat:2 * M_PI];
animation.duration = 1.0f;
animation.fillMode = kCAFillModeForwards;
animation.repeatCount = 2;
animation.removedOnCompletion = NO;
[animation setBeginTime:0.0];
animation.delegate = self;
[animation setValue:#"radarSweep" forKey:#"animName"];
animation.removedOnCompletion = YES;
CABasicAnimation *opacityOutAnimBar = [CABasicAnimation animationWithKeyPath:#"opacity"];
[opacityOutAnimBar setFromValue:[NSNumber numberWithFloat:1.0f]];
[opacityOutAnimBar setToValue:[NSNumber numberWithFloat:0.0f]];
opacityOutAnimBar.delegate = self;
opacityOutAnimBar.fillMode = kCAFillModeForwards;
opacityOutAnimBar.removedOnCompletion = NO;
[opacityOutAnimBar setDuration:0.25];
[opacityOutAnimBar setValue:#"radarSweep" forKey:#"animName"];
[opacityOutAnimBar setBeginTime:1.35];
CAAnimationGroup *group = [CAAnimationGroup animation];
[group setDuration:2.0];
group.delegate = self;
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[group setAnimations:#[opacityInAnim, animation, opacityOutAnimBar]];
[group setValue:#"radarSweep" forKey:#"animName"];
[self.radarView.layer addAnimation:group forKey:#"group"];
Any advice would be greatly appreciated. Thanks in advance.
Your radar image isn't square but the imageview is, so the image is bleeding over the bounds of the imageView. You can either do self.radarView.layer.clipsToBounds = YES or change the content mode to ScaleToFit. Or you can resize your image view to match the proportions of the radar image.
Related
CATextLayer foregroundColor animation don't work on iOS9 but work normal on iOS10 or high version! I don't know what's wrong with my code!
Code as follow:
- (void)addAnimationOnLayer:(CATextLayer*)layer{
CABasicAnimation *colorAn = [CABasicAnimation animationWithKeyPath:#"foregroundColor"];
colorAn.fromValue = (id)NeColor333333.CGColor;
colorAn.toValue = (id)NeColor999999.CGColor;
CABasicAnimation *sizeAn = [CABasicAnimation animationWithKeyPath:#"fontSize"];
sizeAn.fromValue = #16.0;
sizeAn.toValue = #12.0;
CAKeyframeAnimation *keyAn = [CAKeyframeAnimation animationWithKeyPath:#"position"];
keyAn.values = #[[NSValue valueWithCGPoint:layer.position],[NSValue valueWithCGPoint:CGPointMake(layer.position.x, layer.position.y - 16)]];
keyAn.keyTimes =#[#0.0,#1.0];
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = #[colorAn, keyAn, sizeAn];
group.duration = 0.4;
group.repeatCount = 1;
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[layer addAnimation:group forKey:nil];
}
You can add a CALayer, and set CALayer mask is a CATextLayer, you an change CALayer backgroundColor with animation.
I'm trying to animate a pulsting circle. But after the downward scale, there's something of a flickering effect. Any ideas to why that is? Here's my code so far:
- (instancetype)init
{
self = [super init];
if (self) {
if (!self.path) {
self.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(0, 0) radius:7 startAngle:0.0*(M_PI/180.0) endAngle:360.0*(M_PI/180.0) clockwise:YES].CGPath;
}
[self animateCircleUpward];
}
return self;
}
-(void)animateCircleUpward {
[CATransaction begin];
[CATransaction setCompletionBlock:^{[self animateCircleDownward];}];
CABasicAnimation * scaleUpwardAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale.xy"];
scaleUpwardAnimation.fromValue = #(0.7);
scaleUpwardAnimation.toValue = #(1.0);
CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:#"opacity"];
opacityAnimation.fromValue = #(1.0);
opacityAnimation.toValue = #(0.6);
self.fillColor = [UIColor greenColor].CGColor;
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
NSArray *animations = #[scaleUpwardAnimation, opacityAnimation];
animationGroup.duration = 0.4;
animationGroup.animations = animations;
[self addAnimation:animationGroup forKey:#"pulse"];
[CATransaction commit];
}
-(void)animateCircleDownward {
[CATransaction begin];
[CATransaction setCompletionBlock:^{[self animateCircleUpward];}];
CABasicAnimation * scaleDownwardAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale.xy"];
scaleDownwardAnimation.fromValue = #(1.0);
scaleDownwardAnimation.toValue = #(0.7);
CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:#"opacity"];
opacityAnimation.fromValue = #(0.6);
opacityAnimation.toValue = #(1.0);
self.fillColor = [UIColor greenColor].CGColor;
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
NSArray *animations = #[scaleDownwardAnimation, opacityAnimation];
animationGroup.duration = 0.4;
animationGroup.animations = animations;
[self addAnimation:animationGroup forKey:#"pulse"];
[CATransaction commit];
}
#end
Thanx in advance!
In regards to your actual question you likely need to set your CAAnimationGroup's fillMode property to kCAFillModeForward. The default value is kCAFillModeRemoved, so you are likely glimpsing the non-presentation layer between calls back and forth from your Down and Up methods.
That said, it appears that what you're trying to create is a cyclic animation through back and forth calls between your Up and Down methods via CATransaction's completionBlock. This seems an incredibly inefficient approach; why not try something more like:
-(void)scaleAndOpacityAnimations
{
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale.xy”];
scaleAnimation.fromValue = #(0.7f);
scaleAnimation.toValue = #(1.0f);
CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:#“opacity”];
opacityAnimation.fromValue = #(1.0f);
opacityAnimation.toValue = #(0.6f);
CAAnimationGroup *scaleAndOpacity = [CAAnimationGroup animation];
scaleAndOpacity.animations = #[scaleAnimation, opacityAnimation];
scaleAndOpacity.autoReverses = YES;
scaleAndOpacity.repeatCount = HUGE_VALF;
//OP had no value indicated for the duration in posted code, I’m including it here for completion
scaleAndOpacity.duration = 0.5f;
[self addAnimation:scaleAndOpacity forKey:#“pulse”];
}
Which will simply repeat infinitely many times without having to instantiate new CAAnimations on each cycle.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 8 years ago.
Improve this question
I know everything about animation Tools in iOS.
Rotation, Scaling and Moving but I have made a bad timing
for example I have two Squares one on the Left and the Other on the Right
and i want the two squares two rotates until they hit each other with Angle
but i fail to make it because of bad timing
so my Question is their a god tutorial illustrate it
Maybe you can have a look on this link. As Your Tags suggest that you´re using CoreAnimation for that, you can chain your animations.
You could have a fixed moving horizontal and a nested animation with the same duration for rotating. Thats how i do such tasks.
UPDATE:
Here is some code which works perfectly for me:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 70.0, 30.0, 30.0)];
leftView.backgroundColor = [UIColor redColor];
[self.view addSubview:leftView];
UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width, 50.0, 50.0, 50.0)];
rightView.backgroundColor = [UIColor blueColor];
[self.view addSubview:rightView];
[self moveViewLeft:leftView];
[self moveViewRight:rightView];
}
- (void)moveViewLeft:(UIView *)view {
float duration = 1.0;
// Moving
CABasicAnimation *moveAnimation = [CABasicAnimation animationWithKeyPath:#"position"];
moveAnimation.fromValue=[NSValue valueWithCGPoint:CGPointMake([view center].x, [view center].y)];
moveAnimation.toValue=[NSValue valueWithCGPoint:CGPointMake([view center].x+self.view.frame.size.width/2-view.frame.size.width, [view center].y)];
moveAnimation.duration = duration;
moveAnimation.speed = 1.0;
moveAnimation.fillMode = kCAFillModeForwards;
moveAnimation.removedOnCompletion = NO;
// Rotation
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: ((360*M_PI)/180)];
rotationAnimation.duration = duration+0.5;
rotationAnimation.speed = 1.5;
rotationAnimation.fillMode = kCAFillModeForwards;
rotationAnimation.removedOnCompletion = NO;
// Combining Animations
CAAnimationGroup *anim = [CAAnimationGroup animation];
anim.animations = [NSArray arrayWithObjects:moveAnimation, rotationAnimation, nil];
anim.duration = duration;
anim.fillMode = kCAFillModeForwards;
anim.removedOnCompletion = NO;
[view.layer addAnimation:anim forKey:nil];
}
- (void)moveViewRight:(UIView *)view {
float duration = 1.0;
// Moving
CABasicAnimation *moveAnimation = [CABasicAnimation animationWithKeyPath:#"position"];
moveAnimation.fromValue=[NSValue valueWithCGPoint:CGPointMake([view center].x, [view center].y)];
moveAnimation.toValue=[NSValue valueWithCGPoint:CGPointMake([view center].x-self.view.frame.size.width/2, [view center].y)];
moveAnimation.duration = duration;
moveAnimation.speed = 1.0;
moveAnimation.fillMode = kCAFillModeForwards;
moveAnimation.removedOnCompletion = NO;
// Rotation
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: ((360*M_PI)/180)];
rotationAnimation.duration = duration+5;
rotationAnimation.speed = 1.5;
rotationAnimation.fillMode = kCAFillModeForwards;
rotationAnimation.removedOnCompletion = NO;
// Combining Animations
CAAnimationGroup *anim = [CAAnimationGroup animation];
anim.animations = [NSArray arrayWithObjects:moveAnimation, rotationAnimation, nil];
anim.duration = duration;
anim.fillMode = kCAFillModeForwards;
anim.removedOnCompletion = NO;
[view.layer addAnimation:anim forKey:nil];
}
Update 2:
I've changed the duration of the rotation and the speed. Now it looks like your example animation. Both squares are fitting now to each other.
Update 3:
As you say, that you have timing problems, following guide helped me for this:
The duration of the rotation should be equal to the speed.
The duration and the speed should be 150% of the duration and speed of the moving animation.
Are you implementing UICollisionBehavior? If so, try to disable it.
I have a CALayer, and I want to show it and then hide.
CALayer *layerOne = [CALayer layer];
[layerOne addSublayer:textOne];
layerOne.frame = CGRectMake(0, 0, size.width, size.height);
[layerOne setMasksToBounds:YES];
layerOne.opacity = 0.0;
CABasicAnimation *animationOne = [CABasicAnimation animationWithKeyPath:#"opacity"];
[animationOne setDuration:0];
[animationOne setFromValue:[NSNumber numberWithFloat:0.0]];
[animationOne setToValue:[NSNumber numberWithFloat:1.0]];
[animationOne setBeginTime:3];
[animationOne setRemovedOnCompletion:NO];
[animationOne setFillMode:kCAFillModeForwards];
[layerOne addAnimation:animationOne forKey:#"animateOpacity"];
This code work successfully, layerOne appear after 3 seconds.
But I want to hide this layer, so I add this:
CABasicAnimation *animationTwo = [CABasicAnimation animationWithKeyPath:#"opacity"];
[animationTwo setDuration:0];
[animationTwo setFromValue:[NSNumber numberWithFloat:1.0]];
[animationTwo setToValue:[NSNumber numberWithFloat:0.0]];
[animationTwo setBeginTime:6];
[animationTwo setRemovedOnCompletion:NO];
[animationTwo setFillMode:kCAFillModeForwards];
[layerOne addAnimation:animationTwo forKey:#"animateOpacity"];
And it doesn't work. layerOne not appear after 3 seconds. Its just flashed in second 6 and disappear. Its seems like the second animation blocking the first one and only the second animation is going on.
What I do wrong?
Well, for one thing since the second animation has the same key, when you add it to the layer, the original animation will be removed. When the animation is removed, it's long-term effect (setting opacity = 1.0) will also be removed so the animation will be immediately hidden.
For something like this, the normal process to show the layer is:
// set the final result you want to persist forever
layerOne.opacity = 1.0;
// set up your animation here
CABasicAnimation *animationOne = [CABasicAnimation animationWithKeyPath:#"opacity"];
animationOne.fromValue = #(0.);
animationOne.toValue = #(1.);
animationOne.duration = 3.;
animationOne.beginTime = 0.;
animationOne.removedOnCompletion = true;
animationOne.fillMode = kCAFillModeRemove; // for clarity, this is the default
[layerOne addAnimation:animationOne forKey:#"animateOpacity"];
And then when you want to hide the layer just reverse the process:
// Set the final animation state
layerOne.opacity = 0.0;
// set up your animation here
CABasicAnimation *animationTwo = [CABasicAnimation animationWithKeyPath:#"opacity"];
animationTwo.fromValue = #(1.);
animationTwo.toValue = #(0.);
animationTwo.duration = 3.;
animationTwo.beginTime = 0.;
animationTwo.removedOnCompletion = true;
animationTwo.fillMode = kCAFillModeRemove; // for clarity, this is the default
[layerOne addAnimation:animationTwo forKey:#"animateOpacity"];
If you're wanting to run the whole process as a single event, you should put both animations into a single animation group:
// set up your animation here
CABasicAnimation *animationOne = [CABasicAnimation animationWithKeyPath:#"opacity"];
animationOne.fromValue = #(0.);
animationOne.toValue = #(1.);
animationOne.duration = 3.;
animationOne.beginTime = 0.;
animationOne.fillMode = kCAFillModeForwards;
// set up your animation here
CABasicAnimation *animationTwo = [CABasicAnimation animationWithKeyPath:#"opacity"];
animationTwo.fromValue = #(1.);
animationTwo.toValue = #(0.);
animationTwo.beginTime = 6.;
animationTwo.duration = 3.;
animationOne.fillMode = kCAFillModeForwards;
// set up the animation group
CAAnimationGroup* group = [CAAnimationGroup new];
group.beginTime = 0.;
group.duration = 9.;
group.animations = #[ animationOne, animationTwo ];
[layerOne addAnimation:group forKey:#"animateOpacity"];
I'm trying to repeat a sequence of animations, inside a LOOP, changing at each loop some parameters randomly. Here is the code. Anyone please knows why it doesn't work?
If I call it once with a button action, it works, but with a loop it doesn't.
Thanks a lot! Giuseppe
-(IBAction)startLoop:(id)sender {
for (int i=1;i<10; i++) {
[self animation2];
}
}
-(id) animation2 {
int max=500;
UIImage *myImage = [UIImage imageNamed:#"coccinella2.png"];
CALayer *myLayer = [CALayer layer];
myLayer.contents = (id)myImage.CGImage;
myLayer.bounds = CGRectMake(0, 0, 50, 60);
[myLayer setPosition:CGPointMake(arc4random()%(max), arc4random()%(max))];
[myLayer setBounds:CGRectMake(0.0, 0.0, 50.0, 60.0)];
[self.view.layer addSublayer:myLayer];
//translation1
CGPoint startPt = CGPointMake(arc4random()%(max),arc4random()%(max));
CGPoint endPt = CGPointMake(arc4random()%(max),arc4random()%(max));
CABasicAnimation *transl1 = [CABasicAnimation animationWithKeyPath:#"position"];
transl1.removedOnCompletion = FALSE;
transl1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transl1.fromValue = [NSValue valueWithCGPoint:startPt];
transl1.toValue = [NSValue valueWithCGPoint:endPt];
transl1.duration = 2.0;
transl1.fillMode = kCAFillModeForwards;
transl1.beginTime = 0;
//scale 1
CABasicAnimation *scale1 = [CABasicAnimation
animationWithKeyPath:#"transform.scale"];
scale1.removedOnCompletion = FALSE;
[scale1 setToValue:[NSNumber numberWithInt:3]];
[scale1 setDuration:2.0f];
scale1.fillMode = kCAFillModeForwards;
scale1.beginTime = 0;
//rotation1
CABasicAnimation *rotation1 = [CABasicAnimation
animationWithKeyPath:#"transform.rotation.z"];
rotation1.removedOnCompletion = FALSE;
[rotation1 setFromValue:DegreesToNumber(0)];
[rotation1 setToValue:DegreesToNumber(90)];
//rotation1.repeatCount = HUGE_VALF;
[rotation1 setDuration:2.0f];
rotation1.fillMode = kCAFillModeForwards;
rotation1.beginTime = 0;
//group
CAAnimationGroup* group = [CAAnimationGroup animation];
[group setDuration: 6.0];
group.removedOnCompletion = FALSE;
group.fillMode = kCAFillModeForwards;
[group setAnimations: [NSArray arrayWithObjects:scale1, transl1, rotation1, nil]];
[myLayer addAnimation: group forKey: nil];
}
Your code doesn't repeat the annotation 10 times but starts 10 animations right away. If your goal is to start the animations after the previous one ended you should try using an NSTimer.
You can use an NSTimer to trigger each group of animations at a different time, or you can set the beginTime on each group, with code like this:
group.beginTime = CACurrentMediaTime() + delay;
For animations, using the beginTime gives more accurate timing, since CA is run on a separate thread and doesn't stall like NSTimers if your app gets busy.