popspringanimation very choppy in UINavigationController Delegate - ios

In UINavigationController Delegate I add pop animation in the transition, what I did is as following:
- (NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return self.duration;
}
- (void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
UIView *containerView = [transitionContext containerView];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
// I get some cell from initialization
UIImageView *avatarImage = [[UIImageView alloc] initWithFrame:frame];
avatarImage.image = _cell.avatarImageView.image;
avatarImage.clipsToBounds = YES;
avatarImage.layer.cornerRadius = avatarImage.frame.size.width/2.0;
CGFloat originSize = avatarImage.frame.size.width;
[fromViewController.view addSubview:avatarImage];
CGFloat avatarSize = CURRENT_SCREEN_WIDTH * 0.15;
CGFloat avatarPositionY = CURRENT_SCREEN_WIDTH * 0.4;
POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition];
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(CURRENT_SCREEN_WIDTH/2.0, avatarPositionY + avatarSize/2.0 - 64)];
animation.springBounciness = 2.0;
[avatarImage.layer pop_addAnimation:animation forKey:#"move"];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toViewController.view.alpha = 1;
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
[imageView removeFromSuperview];
[avatarImage removeFromSuperview];
}];
}
But the problem is, it's not smooth at all, what is the problem ?

There can be multiple problems;
Your image is very big (in memory)
The corner radius isn't helping either
You're doing something else on the main thread during during this animation
Try the following and see if the animation is smooth after each change:
Remove/comment:
avatarImage.image = _cell.avatarImageView.image;
Remove/comment:
avatarImage.clipsToBounds = YES;
avatarImage.layer.cornerRadius = avatarImage.frame.size.width/2.0;

Related

Objective-c animation with constraints instability issue for trailing constraint

I'm developing an IOS app using objective-c. I came across with an instability problem when animating a view's constraints. The animation works well regarding the final position of the frame, but randomly, the trailing(right) constraint is omitted for the first animation block(left constraint never reach to -20 constant value), however leading(left), top and bottom constraints are working as expected.
Please see the video I uploaded. In the first tap, the animation is working as expected, but in the second tap the issue occurs. Please advice.
Video showing the problem
- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
// 1
UIView *containerView = transitionContext.containerView;
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// 2
[containerView addSubview:toViewController.view];
if([toViewController isKindOfClass:[ImageViewController class]]){
ImageViewController *vcImage = (ImageViewController*)toViewController;
vcImage.constraintLeft.constant = 20;
vcImage.constraintTop.constant = self.selectedCardFrame.origin.y + 60.0;
vcImage.constraintRight.constant = 20.0;
vcImage.constraintBottom.constant = 0;//self.CollectionView.bounds.size.height - (self.selectedCardFrame.origin.y + self.selectedCardFrame.size.height);
[toViewController.view layoutIfNeeded];
NSTimeInterval duration = [self transitionDuration:transitionContext];
[toViewController.view layoutIfNeeded];
[UIView animateWithDuration:duration animations:^{
//First animation block
vcImage.constraintRight.constant = -20.0;
vcImage.constraintLeft.constant = -20.0;
vcImage.constraintTop.constant = -20.0;
vcImage.constraintBottom.constant = 0;
[toViewController.view layoutIfNeeded];
//toViewController.configureRoundedCorners(shouldRound: false)
} completion:^(BOOL finished) {
//Second animation block
[UIView animateWithDuration:duration animations:^{
vcImage.constraintLeft.constant = 0;
vcImage.constraintTop.constant = 0.0;
vcImage.constraintRight.constant = 0;
vcImage.constraintBottom.constant = 0;
[toViewController.view layoutIfNeeded];
//toViewController.configureRoundedCorners(shouldRound: false)
} completion:^(BOOL finished) {
[transitionContext completeTransition:finished];
}];
}];
}
}
Updated code after #Sh_Khan 's comment.
- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
// 1
UIView *containerView = transitionContext.containerView;
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// 2
[containerView addSubview:toViewController.view];
if([toViewController isKindOfClass:[ImageViewController class]]){
ImageViewController *vcImage = (ImageViewController*)toViewController;
NSTimeInterval duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:0 animations:^{
vcImage.constraintLeft.constant = 20;
vcImage.constraintTop.constant = self.selectedCardFrame.origin.y + 60.0;
vcImage.constraintRight.constant = 20.0;
vcImage.constraintBottom.constant = 0;
[toViewController.view layoutIfNeeded];
} completion:^(BOOL finished) {
[UIView animateWithDuration:duration animations:^{
//First animation block
vcImage.constraintRight.constant = -20.0;
vcImage.constraintLeft.constant = -20.0;
vcImage.constraintTop.constant = -20.0;
vcImage.constraintBottom.constant = 0;
[toViewController.view layoutIfNeeded];
//toViewController.configureRoundedCorners(shouldRound: false)
} completion:^(BOOL finished) {
//Second animation block
[UIView animateWithDuration:duration animations:^{
vcImage.constraintLeft.constant = 0;
vcImage.constraintTop.constant = 0.0;
vcImage.constraintRight.constant = 0;
vcImage.constraintBottom.constant = 0;
[toViewController.view layoutIfNeeded];
//toViewController.configureRoundedCorners(shouldRound: false)
} completion:^(BOOL finished) {
[transitionContext completeTransition:finished];
}];
}];
}];
}
}
Before setting your imageView try reorienting the photo. Something tells me the image view is having a hard time determining the orientation of the image. I had this happen during a transition once and would explain why you are seeing the behavior only some of the time. I am a bit rusty with Objective C but give this a shot and use it to before setting your imageView image.
-(UIImage*)normalizeImage:(UIImage*)currentImage {
if (currentImage.imageOrientation == UIImageOrientationUp){
return currentImage;
}
UIGraphicsBeginImageContextWithOptions(currentImage.size, NO, currentImage.scale);
[currentImage drawInRect:CGRectMake(0, 0, currentImage.size.width, currentImage.size.height)];
UIImage *_newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return _newImage;
}

Implment iOS system opening app zoom in/out animation effect

If user turn on the iOS 7 or above dynamic effect, when user taps an app icon, the system will have a zoom out/in effect for the app icon and its view, then go to start the app. I want to achieve similar zoom out/in animation. Any good implementations?
I got most code ready, like below, but not the exact animation I want:
#implementation PushAnimator
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 0.5;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] addSubview:toViewController.view];
toViewController.view.alpha = 0;
UIApplication *app = [UIApplication sharedApplication];
MCAppDelegate *appDelegate = (MCAppDelegate *)app.delegate;
// CGRect fromFrame = appDelegate.UserTouchView.frame;
// CGRect toFrame = toViewController.view.frame;
//
CGFloat xFactor = fromViewController.view.frame.size.width / appDelegate.UserTouchView.frame.size.width;
CGFloat yFactor = fromViewController.view.frame.size.height / appDelegate.UserTouchView.frame.size.height;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
appDelegate.UserTouchView.transform = CGAffineTransformMakeScale(xFactor,yFactor);
toViewController.view.transform = CGAffineTransformMakeScale(1, 1);
toViewController.view.alpha = 1;
} completion:^(BOOL finished) {
fromViewController.view.transform = CGAffineTransformIdentity;
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
#end

Image Animation. Rotate Image like a coin rotation

I have a situation where I have to rotate the image like a coin. I am doing as follows.
CATransition* transition = [CATransition animation];
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.type = #"flip";
transition.subtype = #"fromRight";
transition.duration = 1.0;
transition.repeatCount = 15;
[rotateimageView.layer addAnimation:transition forKey:#"transition"];
It is rotating the image but it is not completely rotating it Please check the video.
https://www.dropbox.com/s/x4t2aqyscgecqfb/animationVideo.mov?dl=0
It looks like rotating but the right pointing arrow never points left. I want it to point left and right as a complete coin animation.
Check out the following article in which I explained how to rotate a banner. Maybe you can apply the same techniques in your application.
http://highoncoding.com/Articles/876_Creating_a_Flipping_Tweets_View.aspx
-
(void) updateFlippingView:(NSTimer *) timer
{
if(index == ([tweets count] -1))
{
index = 0;
}
UILabel *messageLabel = (UILabel *) [flippingView viewWithTag:MESSAGE_LABEL_TAG];
[UIView animateWithDuration:1.0 animations:^{
[UIView animateWithDuration:2.0 animations:^{
messageLabel.alpha = 0.0;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 animations:^{
messageLabel.alpha = 1.0;
messageLabel.text = [tweets objectAtIndex:index];
}];
}];
flippingView.layer.transform = CATransform3DMakeRotation(rotationIndex *M_PI, 1.0, 0.0, 0.0);
for(UIView *subView in flippingView.subviews)
{
subView.layer.transform = CATransform3DMakeRotation(rotationIndex *M_PI, 1.0, 0.0, 0.0);
}
}
completion:^(BOOL finished) {
rotationIndex = rotationIndex == 1 ? 2 :1;
}];
index++;
}

"Glitch" during UIView Intro CAAnimation

I'm trying to add an Animation to a UIView. The objective of the animation is to "animate" the View appearing on screen (instead of just appearing there).
The animation is all size scaling: start from 5%, go up to 120% and then very quickly back to 100% of the regular scale.
My issue is that the full scale UIView appears very quickly, before the animation starts.
Here's the code:
UIView * myView = [[UIView alloc] initWithFrame:someFrame];
[self.view addSubview:myView];
[self initialAnimationFor:myView];
-(void) initialAnimationFor:(UIView*)pView {
const CFTimeInterval firstDuration = 0.75f;
const CFTimeInterval secondDuration = 0.025f;
const float initialValue = 0.05f;
const float middleValue = 1.20f;
CABasicAnimation * firstAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
firstAnimation.duration = firstDuration;
firstAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
firstAnimation.fromValue = [NSNumber numberWithFloat:initialValue];
firstAnimation.toValue = [NSNumber numberWithFloat:middleValue];
CABasicAnimation * secondAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
secondAnimation.duration = secondDuration;
secondAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
secondAnimation.fromValue = [NSNumber numberWithFloat:middleValue];
secondAnimation.toValue = [NSNumber numberWithFloat:1.0f];
CAAnimationGroup *animationGroup = [CAAnimationGroup new];
animationGroup.duration = firstDuration + secondDuration;
animationGroup.animations = #[firstAnimation, secondAnimation];
[pView.layer addAnimation:animationGroup forKey:nil];
}
Any ideas? Thanks!
I would do a different technique and use chained UIView block animations, like this:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(40, 40, 200, 200)];
myView.backgroundColor = [UIColor redColor];
[self initialAnimationFor:myView];
}
- (void)initialAnimationFor:(UIView*)pView {
pView.transform = CGAffineTransformMakeScale(0.05f, 0.05f);
if (pView.superview == nil) {
[self.view addSubview:pView];
}
[UIView
animateWithDuration:0.75f
animations:^{
pView.transform = CGAffineTransformMakeScale(1.20f, 1.20f);
}
completion:^(BOOL finished) {
[UIView
animateWithDuration:0.25f // <-- Your old value of 0.025f makes the animation VERY quick
animations:^{
pView.transform = CGAffineTransformIdentity;
}
];
}
];
}
With this setup, you get the "grow to slightly larger than 100% and then 'settle' to 100%" effect.
Is this a workable solution?

UIViewController Animated Transitioning fails in iOS8

I've got a custom UIViewController transition -- in iOS7, it works perfectly fine.
However, when run on iOS 8, I'm experiencing issues. Specifically, when the presented view controller is dismissed, the original view controller's view disappears entirely - leaving me with a completely blank screen. Here is my code:
#implementation DDCardTransition
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
return 0.5f;
}
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
CGRect endFrame = self.destinationFrame;
if (self.presenting) {
fromViewController.view.userInteractionEnabled = NO;
toViewController.view.layer.cornerRadius = 6.0f;
UIView *tintAdjustmentView = [UIView new];
tintAdjustmentView.frame = fromViewController.view.frame;
tintAdjustmentView.backgroundColor = [UIColor blackColor];
tintAdjustmentView.alpha = 0.f;
[transitionContext.containerView addSubview:fromViewController.view];
[transitionContext.containerView addSubview:tintAdjustmentView];
[transitionContext.containerView addSubview:toViewController.view];
CGRect startFrame = endFrame;
startFrame.origin.y += [UIScreen mainScreen].bounds.size.height;
toViewController.view.frame = startFrame;
[CATransaction begin];
[CATransaction setCompletionBlock:^{
[transitionContext completeTransition:YES];
}];
CABasicAnimation *frameAnimation = [CABasicAnimation animationWithKeyPath:#"position"];
frameAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.1f :0.8f :0.0 :1.0];
frameAnimation.duration = [self transitionDuration:transitionContext];
frameAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(CGRectGetMidX(startFrame), CGRectGetMidY(startFrame))];
frameAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(CGRectGetMidX(endFrame), CGRectGetMidY(endFrame))];
toViewController.view.layer.position = [frameAnimation.toValue CGPointValue];
[toViewController.view.layer addAnimation:frameAnimation forKey:#"position"];
CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:#"opacity"];
opacityAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
opacityAnimation.duration = 0.3f;
opacityAnimation.fromValue = #(0.f);
opacityAnimation.toValue = #(0.5f);
tintAdjustmentView.layer.opacity = [opacityAnimation.toValue floatValue];
[tintAdjustmentView.layer addAnimation:opacityAnimation forKey:#"opacity"];
[CATransaction commit];
}
else {
toViewController.view.userInteractionEnabled = YES;
UIView *tintAdjustmentView = [UIView new];
tintAdjustmentView.frame = toViewController.view.frame;
tintAdjustmentView.backgroundColor = [UIColor blackColor];
tintAdjustmentView.alpha = 0.5f;
[transitionContext.containerView addSubview:toViewController.view];
[transitionContext.containerView addSubview:tintAdjustmentView];
[transitionContext.containerView addSubview:fromViewController.view];
endFrame.origin.y += [UIScreen mainScreen].bounds.size.height;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromViewController.view.frame = endFrame;
tintAdjustmentView.alpha = 0.f;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
}
#end
Any idea why this no longer works in iOS8?
Thanks!
the following code work fine in xcode GM:
func animateTransition(transitionContext: UIViewControllerContextTransitioning!) {
let fromViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
let fromViewControllerView = transitionContext.viewForKey(UITransitionContextFromViewKey)
let containerView = transitionContext.containerView()
fromViewControllerView?.frame = transitionContext.finalFrameForViewController(fromViewController!)
fromViewControllerView?.frame.origin.y = containerView.bounds.height
containerView.addSubview(fromViewControllerView!)
UIView.animateWithDuration(transitionDuration(transitionContext),
delay: 0.0,
options: .AllowUserInteraction,
animations: {
fromViewControllerView!.center.y = containerView.bounds.size.height/2
},
completion: { (completed: Bool) -> Void in
transitionContext.completeTransition(completed)
}
)
}

Resources