I've been looking at the different examples of loading a screen - is there a way to insert a transition screen (sliding) when the a tap is detected? Currently UIImage.imageNamed loads up the next graphic instantly - how to make it slide?
def viewDidLoad
view.image = UIImage.imageNamed('welcome.png')
view.userInteractionEnabled = true
recognizer = UITapGestureRecognizer.alloc.initWithTarget(self, action:'nextScreen')
view.addGestureRecognizer(recognizer)
end
Here is a nextScreen method that should do what you want. With the animation setup, the view.image = ... line will slide the image in from the right.
def nextScreen
animation = CATransition.animation
animation.duration = 0.5
animation.type = KCATransitionMoveIn
animation.subtype = KCATransitionFromRight
view.layer.addAnimation(animation, forKey:'imageTransition')
view.image = UIImage.imageNamed('pic2.png')
end
Source: https://stackoverflow.com/a/5057691/424300
Related
I have a rotating circle shape with 5 subviews and I am animating changes to its fillcolor to match the subview that is currently on top. So when I have to change the color I remove animations from that layer and then add the new one like this:
[self.dynamicColorCircleLayer removeAllAnimations]; //checked - doesn't matter if line is added or not
switch (index) {
case 0: {
CABasicAnimation *fillColorAnimation = [CABasicAnimation animationWithKeyPath:#"fillColor"];
fillColorAnimation.duration = 2;
//fillColorAnimation.fromValue = (id)self.dynamicColorCircleLayer.fillColor;
fillColorAnimation.toValue = (id)[[UIColor redColor] CGColor];
fillColorAnimation.removedOnCompletion = NO;
fillColorAnimation.fillMode = kCAFillModeForwards;
fillColorAnimation.delegate = self;
[self.dynamicColorCircleLayer addAnimation:fillColorAnimation forKey:#"fillColor"];
etc.
And the delegate method:
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
self.dynamicColorCircleLayer.fillColor = (__bridge CGColorRef)(((CABasicAnimation*)theAnimation).toValue);
}
However when one animation hasn't ended and I have to start another, the new one immediately ends.
Fore example: I am animating color change from red to blue, I'm in the middle of animation and I have to animate color change to green. The animation isn't showing, circle just immediately changes color to green.
If I remove code from animationDidStop(...), I will get an animation to green, but every animation will start from the default (red) color.
What is the right way to interrupt animation with another animation? Also, is it even possible to make the new animation start from the color it had at the moment when I removed the older animation? (In the example above, it would be animating color change to green from a color between red and blue)
Refer this question:
Is there a way to pause a CABasicAnimation?
Here first answer explains how to pause existing animation and the second answer says how to stop the same.
Hope this is what you are looking for.
I found a way to do this, however I still have no idea how to start the next animation from the color at which the previous one was stopped. Here it is in case anyone will need it:
CABasicAnimation *currentAnimation = (CABasicAnimation*)[self.dynamicColorCircleLayer animationForKey:#"fillColor"];
if (currentAnimation != nil) {
self.dynamicColorCircleLayer.fillColor = (__bridge CGColorRef)(currentAnimation.toValue);
}
switch (index) {
case 0: {
CABasicAnimation *fillColorAnimation = [CABasicAnimation animationWithKeyPath:#"fillColor"];
fillColorAnimation.duration = 2.5f;
fillColorAnimation.toValue = (id)[[UIColor redColor] CGColor];
fillColorAnimation.removedOnCompletion = NO;
fillColorAnimation.fillMode = kCAFillModeForwards;
fillColorAnimation.delegate = self;
[self.dynamicColorCircleLayer addAnimation:fillColorAnimation forKey:#"fillColor"];
break;
} (...)
And in the delegate method:
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
if (flag) {
self.dynamicColorCircleLayer.fillColor = (__bridge CGColorRef)(((CABasicAnimation*)theAnimation).toValue);
}
}
Now, when i.e. animation that changes color to green is either succesfully finished or interrupted early, fillcolor will just change to green and begin next animation if needed.
I've hit a wall here. I know how to move an Image using "CGAffineTransformMakeTranslation" and I also know how to scale an image using"CGAffineTransformMakeScale" but for the life of me, I can't seem to get one Image to do both of these and stay that way. It scales to the desired size for about a split second and then immediately reverts to its original size and moves to the desired location. What I need is for the image to get big, STAY big, and then move to a new location (while permanently staying its new size).
Here is what I've got going on in my .m file:
-(IBAction)PushZoomButton {
[UIWindow animateWithDuration:1.5
animations:^{
JustinFrame.transform = CGAffineTransformMakeScale(2.0, 2.0);
JustinFrame.transform = CGAffineTransformMakeTranslation(10.0, 10.0);}];
[UIWindow commitAnimations];}
Any help with this would be appreciated!
you can use CGAffineTransformConcat, for instance:
JustinFrame.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(2.0, 2.0), CGAffineTransformMakeTranslation(10.0, 10.0));
You may need to adapt the translation to (5, 5) since you have doubled the scale
The second transform you set overrides the first one. You need to concat both transform actions into one, as Luis said. Another way of writing that would be:
CGAffineTransform transform = CGAffineTransformMakeScale(2.0, 2.0);
transform = CGAffineTransformTranslate(transform, 10, 10);
JustinFrame.transform = transform;
You may need to look into CoreAnimation, basically what UIView animation is controlling under the hood. If you set up a CAAnimation, then what you want to achieve is done with the fillMode property of the animation.
Here's some example code to make a UIView look like it's opening like a door (copy pasted some code I have, but perhaps you could modify it and find it useful):
- (void) pageOpenView:(UIView *)viewToOpen duration:(NSTimeInterval)duration pageTurnDirection:(PageTurnDirection) p{
// Remove existing animations before stating new animation
[viewToOpen.layer removeAllAnimations];
// Make sure view is visible
viewToOpen.hidden = NO;
// disable the view so it’s not doing anythign while animating
viewToOpen.userInteractionEnabled = NO;
float dir = p == 0 ? -1.0f : 1.0f; // for direction calculations
// create an animation to hold the page turning
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:#"transform"];
transformAnimation.removedOnCompletion = NO;
transformAnimation.duration = duration;
transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
CATransform3D startTransform = CATransform3DIdentity;
if (p == NEXT_PAGE) {
// orig values
startTransform.m34 = 0.001f;
}else {
// orig values
startTransform.m34 = -0.001f;
}
// start the animation from the current state
transformAnimation.fromValue = [NSValue valueWithCATransform3D:startTransform];
// this is the basic rotation by 90 degree along the y-axis
CATransform3D endTransform = CATransform3DMakeRotation(3.141f/2.0f,
0.0f,
dir,
0.0f);
// these values control the 3D projection outlook
if (p == NEXT_PAGE) {
endTransform.m34 = 0.001f;
endTransform.m14 = -0.0015f;
}else {
endTransform.m34 = -0.001f;
endTransform.m14 = 0.0015f;
}
transformAnimation.toValue = [NSValue valueWithCATransform3D:endTransform];
// Create an animation group to hold the rotation
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
// Set self as the delegate to receive notification when the animation finishes
theGroup.delegate = self;
theGroup.duration = duration;
// CAAnimation-objects support arbitrary Key-Value pairs, we add the UIView tag
// to identify the animation later when it finishes
[theGroup setValue:[NSNumber numberWithInt:[(BODBookPageView *)viewToOpen pageNum]] forKey:#"animateViewPageNum"]; //STEPHEN: We set the tag to the page number
[theGroup setValue:[NSNumber numberWithInt: p] forKey:#"PageTurnDirection"];
[theGroup setValue:[NSNumber numberWithBool:YES] forKey:#"isAnimationMidpoint"]; // i.e. is this the first half of page-turning or not?
// Here you could add other animations to the array
theGroup.animations = [NSArray arrayWithObjects:transformAnimation, nil];
theGroup.removedOnCompletion = NO; // THIS LINE AND THE LINE BELOW WERE CRUCIAL TO GET RID OF A VERY HARD TO FIND/FIX BUG.
theGroup.fillMode = kCAFillModeForwards; // THIS MEANS THE ANIMATION LAYER WILL STAY IN THE STATE THE ANIMATION ENDED IN, THEREBY PREVENTING THAT ONE FRAME FLICKER BUG.
// Add the animation group to the layer
[viewToOpen.layer addAnimation:theGroup forKey:#"flipViewOpen"];
}
So I am trying to create an animated bar graph using apple core animation. The bar is just basically a rectangular figure, which have a value of 0-100%. When it first appears I wanted it to show an animation going from 0 to x %. How can I draw a rectangular form like this?
UPDATE:
Most probably I will have a bar as an image, so I need to animate this image to a certain height...
If your requirements are really that simple, you could create a view, set its background color and adjust (or animate) its frame.width (or height) as needed.
Of course there are more elaborate ways to do this, but no need to over-engineer for a simple problem.
This should do exactly what you want:
- (UIImageView*)createNewBarWithValue:(float)percent atLocation:(CGPoint)location
{
UIImageView *newBar = [[[UIImageView alloc] initWithFrame:CGRectMake(location.x, location.y, 50, 200)] autorelease];
newBar.image = [UIImage imageNamed:#"bar.png"];
CABasicAnimation *scaleToValue = [CABasicAnimation animationWithKeyPath:#"transform.scale.y"];
scaleToValue.toValue = [NSNumber numberWithFloat:percent];
scaleToValue.fromValue = [NSNumber numberWithFloat:0];
scaleToValue.duration = 1.0f;
scaleToValue.delegate = self;
newBar.layer.anchorPoint = CGPointMake(0.5, 1);
[newBar.layer addAnimation:scaleToValue forKey:#"scaleUp"];
CGAffineTransform scaleTo = CGAffineTransformMakeScale( 1.0f, percent );
newBar.transform = scaleTo;
return newBar;
}
This is my first question her so please be gentle:
I have followig animation code running smoothly on the simulator as well as on the real device (I am testng on iPhone 3GS 3.1.2).
Animation is a simple transition between the 2 views, something like book page flipping.
One diffrence betwen simulator an real device (The problem I cannot investigate - solve) is that on real device when animation finishes - after rotation has been done animated view blink (show for a split of second) for a moment before it goes hidden. On the simulator this 'unexpected' blink does not happen.
Here is the animation code:
-(void)flip{
UIView *animatedView;
// create an animation to hold the page turning
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:#"transform"];
transformAnimation.removedOnCompletion = NO;
transformAnimation.delegate = self;
transformAnimation.duration = ANIMATION_TIME;
transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
// this is the basic rotation by 90 degree along the y-axis
CATransform3D endTransform = CATransform3DMakeRotation(3.141f/2.0f,
0.0f,
-1.0f,
0.0f);
// these values control the 3D projection outlook
endTransform.m34 = 0.001f;
endTransform.m14 = -0.0015f;
// start the animation from the current state
transformAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
transformAnimation.toValue = [NSValue valueWithCATransform3D:endTransform];
animatedView = screenShot;
// Create an animation group to hold the rotation and possibly more complex animation in the future
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
// Set self as the delegate to receive notification when the animation finishes
theGroup.delegate = self;
theGroup.duration = ANIMATION_TIME;
// CAAnimation-objects support arbitrary Key-Value pairs, we add the UIView tag
// to identify the animation later when it finishes
[theGroup setValue:[NSNumber numberWithInt:animatedView.tag] forKey:#"animated"];
// Here you could add other animations to the array
theGroup.animations = [NSArray arrayWithObjects:transformAnimation,nil];
theGroup.removedOnCompletion = NO;
// Add the animation group to the layer
if (animatedView.layer.anchorPoint.x != 0.0f)
{
animatedView.layer.anchorPoint = CGPointMake(0.0f, 0.5f);
float yy = animatedView.center.x - (animatedView.bounds.size.width / 2.0f);
animatedView.center = CGPointMake(yy, animatedView.center.y);
}
if(![animatedView isDescendantOfView:self.view])[self.view addSubview:animatedView];
screenShot.hidden = NO;
animatedView.hidden = NO;
[animatedView.layer addAnimation:theGroup forKey:#"flip"];
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
screenShot.hidden = YES;
}
Try setting theGroup's and / or transformAnimation's fillMode to kCAFillModeForwards:
theGroup.fillMode = kCAFillModeForwards;
This should cause your animation to persist once its active duration has completed. I've used this to remove an end-of-animation flicker before.
Not sure I understand completely what you are seeing but it's possible you're seeing something caused by the speed difference between the device and the simulator. The simulator is considerably faster than the device so something that "blinks" very quickly might do so too fast for the human eye to catch on the simulator.
Oof. That's annoying. I think it is that there's a split-second between when animation stops and when that line of code executes. If only there were an animationWillStop: method! You might try, instead of screenShot.hidden = YES, screenShot.alpha = 0. I doubt it will make any difference speed-wise, but it might be worth a shot? You could also fade out the view as part of the animation, but I don't think you want to do that.
The only other thing I can think of is to setup an NSTimer with an interval just under your animation time. Something like:
[NSTimer scheduledTimerWithTimeInterval:(ANIMATION_TIME - .001) target:self selector:#selector(hideTheView) userInfo:nil repeats:NO];
And then implement that hideTheView method, of course.
I'm trying to scale an image down, change the image, then scale it back up.
CABasicAnimation* shrink = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
shrink.toValue = [NSNumber numberWithDouble:0];
shrink.duration = 1;
shrink.delegate = self;
[myImageView.layer addAnimation:shrink forKey:#"shrink"];
makes the shrink, then when it completes, I change the image, and start the grow:
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
myImageView.image = [images objectAtIndex:image];
CABasicAnimation* grow = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
grow.toValue = CGAffineTransformMakeScale(1,1);
grow.delegate = self;
grow.duration = 1;
[myImageView.layer addAnimation:grow forKey:#"grow"];
}
This works great on the simulator, but on the device, when the shrink completes, I get a flash of the full-size, old image, then the grow animation begins with the new image.
Any idea how to get rid of that flash?
(I've tried "removedOnCompletion = NO;" and attempted setting the affineTransform equal to the scaled down size after the first completion, but didn't have much luck.)
Any tips appreciated.
kb
Edit:
Excellent! Setting the following:
shrink.fillMode = kCAFillModeForwards;
shrink.removedOnCompletion = NO;
Removed the flashing. Thanks, Ben!
Try setting your animation's fillMode to kCAFillModeForwards. That should leave the item as it was at the end of the animation, rather than before.
I've had the same problem when I tried to create another CAAnimation in the animationDidStop method. I suggest using CAKeyframeAnimation.