CATransition animation zoom change image (UIImageView) - uiimageview

I try to achieve zooming animation image change on UIImageView.
So far I created a transition of type moveIn and subtype fromLeft:
CATransition *transition = [CATransition animation];
[transition setSubtype:kCATransitionFromLeft];
[transition setType:kCATransitionMoveIn];
[transition setDuration:1.5];
[[imageView layer] addAnimation:transition forKey:nil];
But I want a zooming effect. I successfully created it by using CABasicAnimation:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transition.scale"];
[animation setFromValue:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0, 0.0, 1.0)]];
[animation setToValue:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1.0)]];
[animation setDuration:1.5];
[[imageView layer] addAnimation:animation forKey:nil];
My problem is that, using the second approach, the image changes (old image is gone) and then the animation comes in.
So it's an animation and not transition (as the names imply).
How can I create a transition with zoom effect?

Can use this to scale.
setTransform:CGAffineTransformMakeScale

Related

Invert Core Animation Direction

How can i change the vertical Direction of an Animation?
Currently i have this:
-(void) flipAway{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform"];
self.view.layer.zPosition = 100;
CATransform3D transform = CATransform3DMakeRotation(M_PI, 1, 0, 0);
transform.m34 = 1.0/800.0;
[animation setToValue:[NSValue valueWithCATransform3D:transform]];
[animation setDuration:5];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
[animation setFillMode:kCAFillModeForwards];
[animation setRemovedOnCompletion:NO];
[animation setDelegate:self];
[self.view.layer addAnimation:animation forKey:#"test"];
}
And this works, BUT the rotation is a flip from top to bottom, how can i invert this to be from bottom to top?
Not sure what you're asking for.
CATransform3D transform = CATransform3DMakeRotation(- M_PI, 1, 0, 0);
The target was to invert Animation Direction : instead from bottom to top , i wanted to have it from top to bottom, i finally achieved this by adding an anchor Point for the animation:
CGRect frame = self.view.layer.frame;
CGPoint center = CGPointMake(CGRectGetMidX(frame), frame.size.height);
self.view.layer.position = center;
self.view.layer.anchorPoint = CGPointMake(0.5, 1);
I don't know why, but once you add this lines, the animation inverts..

NSView resizing shaky

I have an MAAttachedWindow (subclass of NSWindow), which contains a blank view (contentView), and some arbitrary subview (right now an NSImageView).
On load, I'm attempting to resize the window by 100px vertically, in an animated fashion.
This code block initializes my window and views:
_popoverContentView = [[NSView alloc] initWithFrame: aFrame];
NSImageView *img = [[NSImageView alloc] initWithFrame: aFrame];
[img setImage: [NSImage imageName: "#my_debug_image"]];
[img setAutoresizingMask: NSViewHeighSizable];
[_popoverContentView setAutoresizesSubviews: YES];
[_popoverContentView addSubview: img];
popover = [[MAAttachedWindow alloc] initWithView: _popoverContentView attachedToPoint: aPoint inWindow: nil onSide: MAPositionBottom atDistance: aDist];
And this code block is responsible for the animation:
NSRect newPopoverFrame = popover.frame;
NSRect newPopoverContentViewFrame = _popoverContentView.frame;
newPopoverFrame.size.height += 100;
newPopoverContentViewFrame.size.height += 100;
[_popoverContentView animator] setFrame: newPopoverContentViewFrame];
[[popover animator] setFrame: newPopoverFrame display: YES animate: YES];
Now this all works (almost) as expect, however as shown in this video, the animation is unreliable, shaky, and jumpy. I can't seem to pinpoint what in my code is causing this, or how to go about locking the image view into place.
I think the problem is that you're using the new(ish) animator proxy to animate the window's frame while also using the much older animate: parameter of NSWindow's setFrame:display:animate:, which uses the old NSViewAnimation API.
These two animation methods are probably conflicting as they try to animate the window simultaneously using different code paths.
You also need to wrap multiple calls to the animator proxy in [NSAnimationContext beginGrouping] and [NSAnimationContext endGrouping] if you wish the animations to be simultaneous.
Try doing this:
[NSAnimationContext beginGrouping];
[_popoverContentView animator] setFrame: newPopoverContentViewFrame];
[[popover animator] setFrame: newPopoverFrame display: YES animate:NO];
[NSAnimationContext endGrouping];
If that doesn't work, you could drop the use of the problematic setFrame:display:animate: method and just animate the position and size independently:
[NSAnimationContext beginGrouping];
[_popoverContentView animator] setFrame: newPopoverContentViewFrame];
[[popover animator] setFrameOrigin: newPopoverFrame.origin];
[[popover animator] setFrameSize: newPopoverFrame.size];
[NSAnimationContext endGrouping];
The animation context grouping will ensure that everything happens simultaneously.

Animation doesn't show

Here is my code snippet for cocoa application using core animation, somehow the animation doesn't show.
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"position"];
[animation setDelegate:self];
NSRect pos = [imageView frame];
[animation setFromValue:[NSValue valueWithRect:pos]];
NSPoint point = NSMakePoint(pos.origin.x-40, pos.origin.y);
[animation setToValue:[NSValue valueWithPoint:point]];
[animation setDuration:2.0];
[[imageView animator] addAnimation:animation forKey:#"myTest"];
while this is the working code:
NSRect position = [imageView frame];
position.origin.x -= 40;
[[imageView animator] setFrame:position];
But autoReverse doesn't work.
Anything wrong with the first one? And how to make the reverse movement work in the 2nd one? Thanks!
I don't know for sure, but for the first one, position is a CGPoint, so you might try using that type for your fromValue and toValue. You're currently using an NSRect and an NSPoint (the latter of which should work, but not sure about the former).
For the second, how are you specifying auto-reverse? +setAnimationRepeatAutoreverses needs to be called from inside an animation block (after "beginAnimations")
(Note: I'm not very experienced with Cocoa since I'm chiefly an iOS developer; I haven't tested any of the following stuff)
I think the problem is that you're trying to mix CoreAnimation and Animator Proxy. You don't add the animation to the Animator, but to the layer:
[[imageView layer] addAnimation:animation forKey:#"myTest"];
Another possibility might be to use NSViewAnimation and chain them together. See the Animation Programming Guide for Cocoa, page 13. So you'd have one animation to go in one direction, and once it's finished it triggers the second one that goes back. It seems to work like this:
NSMutableDictionary *firstDict = [NSMutableDictionary dictionary];
[firstDict setObject:imageView forKey:NSViewAnimationTargetKey];
[firstDict setObject:[NSValue valueWithRect:originalFrame] forKey:NSViewAnimationStartFrameKey];
[firstDict setObject:[NSValue valueWithRect:targetFrame] forKey:NSViewAnimationEndFrameKey];
NSMutableDictionary *secondDict = [NSMutableDictionary dictionary];
[secondDict setObject:imageView forKey:NSViewAnimationTargetKey];
[secondDict setObject:[NSValue valueWithRect:targetFrame] forKey:NSViewAnimationStartFrameKey];
[secondDict setObject:[NSValue valueWithRect:originalFrame] forKey:NSViewAnimationEndFrameKey];
NSViewAnimation *firstAnimation = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:firstDict]];
[firstAnimation setDuration:2.0];
NSViewAnimation *secondAnimation = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:secondDict]];
[secondAnimation setDuration:2.0];
[secondAnimation startWhenAnimation:firstAnimation reachesProgress:1.0];
[firstAnimation startAnimation];
Then, in Lion (OS X 10.7) you can set a completion handler when using Animator Proxy. It should work like this:
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:2.0];
[[NSAnimationContext currentContext] setCompletionHandler:^(void) {
// Here comes your code for the reverse animation.
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:2.0];
[[aView animator] setFrameOrigin:originalPosition];
[NSAnimationContext endGrouping];
}];
[[aView animator] setFrameOrigin:position];
[NSAnimationContext endGrouping];

iPhone - UINavigationController - custom animation with CATransaction

I am trying to create a category for UINavigationController so I can put together a few custom animations. I came across this question and it got me started. I've come up with the following for a push function:
- (void)pushViewControllerMoveInFromBottom:(UIViewController *)viewController {
[CATransaction begin];
CATransition *transition;
transition = [CATransition animation];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromBottom;
transition.duration = 0.7;
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
[[[[self.view subviews] objectAtIndex:0] layer] addAnimation:transition forKey:nil];
[self pushViewController:viewController animated:YES];
[CATransaction commit];
}
I don't understand which view/layer is being accessed via the subview call. So if someone could help me understand that, that would be helpful. It seems to be effecting whatever view is about to come onto the screen.
But my main question is that I'm trying to create a pop that will "undo" the above function. For clarity sake, lets say I have two views, A and B. A is the first view that is shown on the screen. The function above, will move in B without pushing A out. Much like a modal view would. But the function below slides A back in over B, rather that sliding B up and leaving A in place.
- (void)popViewControllerMoveInFromTop {
[CATransaction begin];
CATransition *transition;
transition = [CATransition animation];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromTop;
transition.duration = 0.7;
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
[[[[self.view subviews] objectAtIndex:0] layer] addAnimation:transition forKey:nil];
[self popViewControllerAnimated:YES];
[CATransaction commit];
}
I don't want to use a modal view and I would rather not use custom animation blocks to change the frame of the views.
I've accomplished something similar, though I didn't bother to move it into it's own function:
CATransition *transition = [CATransition animation];
transition.duration = 0.5;
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromBottom;
[self.navigationController.view.layer addAnimation:transition forKey:nil];
[self.navigationController popViewControllerAnimated:NO]
You could abstract it out. Using your code, it would look like:
- (void)popViewControllerMoveInFromTop {
[CATransaction begin];
CATransition *transition;
transition = [CATransition animation];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromTop;
transition.duration = 0.7;
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
[self.view.layer addAnimation:transition forKey:nil];
[self popViewControllerAnimated:NO];
[CATransaction commit];
}
You can also create a custom transition for pop using UIView's animations. Here you are applying an animation to the view that's about to disappear and then popping it from the view stack:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.75];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
[self.navigationController popViewControllerAnimated:NO];
[UIView commitAnimations];

How can I animate a content switch in an NSImageView?

I want to switch the image shown in an NSImageView, but I want to animate that change. I've tried various methods to do this. Hopefully one of you could suggest one that might actually work. I'm working with Cocoa for Mac.
As far as I know, NSImageView doesn't support animating image changes. However, you can place a second NSImageView on top of the first one and animate hiding the old one and showing the new one. For example:
NSImageView *newImageView = [[NSImageView alloc] initWithFrame: [imageView frame]];
[newImageView setImageFrameStyle: [imageView imageFrameStyle]];
// anything else you need to copy properties from the old image view
// ...or unarchive it from a nib
[newImageView setImage: [NSImage imageNamed: #"NSAdvanced"]];
[[imageView superview] addSubview: newImageView
positioned: NSWindowAbove relativeTo: imageView];
[newImageView release];
NSDictionary *fadeIn = [NSDictionary dictionaryWithObjectsAndKeys:
newImageView, NSViewAnimationTargetKey,
NSViewAnimationFadeInEffect, NSViewAnimationEffectKey,
nil];
NSDictionary *fadeOut = [NSDictionary dictionaryWithObjectsAndKeys:
imageView, NSViewAnimationTargetKey,
NSViewAnimationFadeOutEffect, NSViewAnimationEffectKey,
nil];
NSViewAnimation *animation = [[NSViewAnimation alloc] initWithViewAnimations:
[NSArray arrayWithObjects: fadeOut, fadeIn, nil]];
[animation setAnimationBlockingMode: NSAnimationBlocking];
[animation setDuration: 2.0];
[animation setAnimationCurve: NSAnimationEaseInOut];
[animation startAnimation];
[imageView removeFromSuperview];
imageView = newImageView;
[animation release];
If your view is big and you can require 10.5+, then you could do the same thing with Core Animation, which will be hardware accelerated and use a lot less CPU.
After creating newImageView, do something like:
[newImageView setAlphaValue: 0];
[newImageView setWantsLayer: YES];
// ...
[self performSelector: #selector(animateNewImageView:) withObject: newImageView afterDelay: 0];
- (void)animateNewImageView:(NSImageView *)newImageView;
{
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration: 2];
[[newImageView animator] setAlphaValue: 1];
[[imageView animator] setAlphaValue: 0];
[NSAnimationContext endGrouping];
}
You'll need to modify the above to be abortable, but I'm not going to write all your code for you :-)
You could implement your own custom view that uses a Core Animation CALayer to store the image. When you set the contents property of the layer, the image will automatically smoothly animate from the old image to the new one.

Resources