UIViewController Animated Transitioning fails in iOS8 - ios

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)
}
)
}

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;
}

popspringanimation very choppy in UINavigationController Delegate

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;

Animation does not work after the first time to return to the original state

I have two UIImages one over another, with the same size (40 by 40) it's a simple dot on the whole UIImage and I want to animate rotating as a 3D. When the first UIImage "colapse" and it is not visible, change the property HIDDEN to YES, and immediately the UIImage under the first begin to appears, and when the user press the button again everything turn back at the first state. But i works only the first time, after that, just appears and disappears the images.
Heres is my code:
#interface ViewController ()
{
BOOL myFlag;
}
#end
- (void)viewDidLoad {
[super viewDidLoad];
self.C002.image = [Test imageOfCircle002];
self.C005.image = [Test imageOfCircle005];
self.C005.hidden = YES;
myFlag = YES;
}
- (IBAction)animationButton:(id)sender
{
if (myFlag)
{
//First state of the UIImages,
[UIView animateWithDuration:1.0 animations:^{
//3D rotation C002
CABasicAnimation* animation;
animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
animation.fromValue = #(0);
animation.toValue = #(0.5 * M_PI);
animation.repeatCount = 1;
animation.duration = 1.0;
[self.C002.layer addAnimation:animation forKey:#"rotation"];
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0 / 500.0;
self.C002.layer.transform = transform;
} completion:^(BOOL finished) {
self.C002.hidden = YES; //Hide the first image
self.C005.hidden = NO; //Show the second and animate
[UIView animateWithDuration:1.0 animations:^{
//3D rotation C005
CABasicAnimation* animation2 = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
animation2.fromValue = #(0.5 * M_PI); //begin where the first UIImage ends
animation2.toValue = #(1.0 * M_PI);
animation2.repeatCount = 1;
animation2.duration = 1.0;
[self.C005.layer addAnimation:animation2 forKey:#"rotation"];
CATransform3D transform2 = CATransform3DIdentity;
transform2.m34 = 1.0 / 500.0;
self.C005.layer.transform = transform2;
} completion:^(BOOL finished) {
[self.C002.layer removeAnimationForKey:#"rotation"];
[self.C005.layer removeAnimationForKey:#"rotation"];
}];
}];
myFlag = NO; // Set the flag to other state.
}
else
{ //Heres try to turn everything back, but... not working.
[UIView animateWithDuration:1.0 animations:^{
//3D rotation C005
CABasicAnimation* animation;
animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
animation.fromValue = #(1.0 * M_PI); //begin where is in the last animation
animation.toValue = #(0.5 * M_PI);
animation.repeatCount = 1;
animation.duration = 1.0;
[self.C005.layer addAnimation:animation forKey:#"rotation"];
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0 / 500.0;
self.C005.layer.transform = transform;
} completion:^(BOOL finished) {
self.C005.hidden = YES;
self.C002.hidden = NO;
[UIView animateWithDuration:1.0 animations:^{
//3D rotation C002
CABasicAnimation* animation2 = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
animation2.fromValue = #(0.5 * M_PI);
animation2.toValue = #(0 * M_PI);
animation2.repeatCount = 1;
animation2.duration = 1.0;
[self.C002.layer addAnimation:animation2 forKey:#"rotation"];
CATransform3D transform2 = CATransform3DIdentity;
transform2.m34 = 1.0 / 500.0;
self.C002.layer.transform = transform2;
} completion:^(BOOL finished) {
[self.C002.layer removeAnimationForKey:#"rotation"];
[self.C005.layer removeAnimationForKey:#"rotation"];
}];
}];
myFlag = YES;
}
}
Hope guys, you can help me.

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++;
}

UIViewControllerAnimatedTransitioning in iOS7 - viewWillAppear not called

I'm trying to get the hang of the new viewController animations in ios7 but I am encountering a road bump when trying to use core animation.
Im finding that after the transition has completed, the controller of the 'to view' does not seem to be receiving the typical view lifecycle methods, i.e. viewWillAppear and viewDidAppear. I'm calling completeTransition: but that doest seem to be enough -- is this typical behavior? Or am I doing something wrong? here is my code:
-(void)executeDismissalAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
UIView *inView = [transitionContext containerView];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
toViewController.view.hidden = NO;
[CATransaction begin];
[CATransaction setCompletionBlock:^{
[fromViewController.view removeFromSuperview];
[transitionContext completeTransition:YES];
}];
CGFloat duration = 0.4f;
CAKeyframeAnimation *scaleAnimation = [CAKeyframeAnimation animationWithKeyPath:#"transform.scale"];
scaleAnimation.values = [self floatValuesFromValue:1.f toValue:1.5f withEasingFunction:ExponentialEaseInOut];
scaleAnimation.duration = duration;
scaleAnimation.fillMode = kCAFillModeForwards;
scaleAnimation.removedOnCompletion = YES;
[fromViewController.view.layer addAnimation:scaleAnimation forKey:nil];
CAKeyframeAnimation *alphaAnimation = [CAKeyframeAnimation animationWithKeyPath:#"opacity"];
alphaAnimation.values = [self floatValuesFromValue:1.f toValue:0.f withEasingFunction:LinearInterpolation];
alphaAnimation.duration = duration*2;
alphaAnimation.fillMode = kCAFillModeForwards;
alphaAnimation.removedOnCompletion = YES;
[fromViewController.view.layer addAnimation:alphaAnimation forKey:nil];
CAKeyframeAnimation *scaleAnimationB = [CAKeyframeAnimation animationWithKeyPath:#"transform.scale"];
scaleAnimationB.values = [self floatValuesFromValue:0.6f toValue:1.0f withEasingFunction:ExponentialEaseInOut];
scaleAnimationB.duration = duration;
scaleAnimationB.beginTime = CACurrentMediaTime()+0.3;
scaleAnimationB.fillMode = kCAFillModeForwards;
scaleAnimationB.removedOnCompletion = NO;
[toViewController.view.layer addAnimation:scaleAnimationB forKey:nil];
CAKeyframeAnimation *alphaAnimationB = [CAKeyframeAnimation animationWithKeyPath:#"opacity"];
alphaAnimationB.values = [self floatValuesFromValue:0.5f toValue:1.f withEasingFunction:LinearInterpolation];
alphaAnimationB.duration = duration;
alphaAnimationB.beginTime = CACurrentMediaTime()+0.3;
alphaAnimationB.fillMode = kCAFillModeForwards;
alphaAnimationB.removedOnCompletion = NO;
[toViewController.view.layer addAnimation:alphaAnimationB forKey:nil];
[CATransaction commit];
}

Resources