Search code examples
iosuiviewanimationflipuiviewanimationtransition

UIview Flip darkens the Views


I've been implementing a simple FlipView in iOS : A UIView that contains two subviews, displaying one at a time, and when you click on it, it flips them. I'm using the following to animate the flipping.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    @synchronized(self){
        if(!self.flipping){
            self.flipping = YES;
            UIView *toView = self.currentView == self.primaryView ? self.secondaryView : self.primaryView;            
            [UIView transitionFromView:self.currentView toView:toView duration:self.speed options:UIViewAnimationOptionTransitionFlipFromLeft|UIViewAnimationOptionCurveEaseInOut completion:^(BOOL finished) {
                [self.currentView removeFromSuperview];
                self.currentView = toView;
                self.flipping = NO;
            }];                
        }
    }
}

Pretty straight forward, right ?

But what bugs me is that, while the views are flip, the flipped content is darkened. Which shows, against a light background.

Would anyone knows a solution to have the exact same animation, but without the darkening (<= is that even a word ?)

Thanks in advance !

PS : I'm targeting IOS 5 and above.


Solution

  • I succeeded, getting inspiration in the code I found here http://www.mycodestudio.com/blog/2011/01/10/coreanimation/ (and he, himself, took inspiration from http://www.mentalfaculty.com/mentalfaculty/Blog/Entries/2010/9/22_FLIPPIN_OUT_AT_NSVIEW.html)

    Anyway, what I do spin between two views.

    - (void)flip{
        @synchronized(self){
            if(!self.flipping){
                self.flipping = YES;
    
                UIView *bottomView = self.currentView == self.primaryView ? self.secondaryView : self.primaryView;
                CALayer *top = self.currentView.layer;
                CALayer *bot = bottomView.layer;
    
                CAAnimation *topAnimation = [self flipAnimationWithDuration:self.speed/2.0 forLayerBeginningOnTop:YES scaleFactor:1];
                CAAnimation *bottomAnimation = [self flipAnimationWithDuration:self.speed/2.0 forLayerBeginningOnTop:NO scaleFactor:1];
    
                CGFloat zDistance = 1500.0f;
                CATransform3D perspective = CATransform3DIdentity;
                perspective.m34 = -1. / zDistance;
                top.transform = perspective;
                bot.transform = perspective;
    
                topAnimation.delegate = self;
                [CATransaction setCompletionBlock:^{
                    [top removeAllAnimations];
                    [self.currentView removeFromSuperview];
                    self.currentView = bottomView;
                    [self addSubview:bottomView];
    
                    [CATransaction setCompletionBlock:^{
                        self.flipping = NO;
                        [bot removeAllAnimations];
                    }];
                    [CATransaction begin];
    
                    [bot addAnimation:bottomAnimation forKey:@"flip"];
    
                    [CATransaction commit];
                }];
                [CATransaction begin];
                [top addAnimation:topAnimation forKey:@"flip"];
    
                [CATransaction commit];
            }
        }
    }
    
    -(CAAnimation *)flipAnimationWithDuration:(NSTimeInterval)aDuration forLayerBeginningOnTop:(BOOL)beginsOnTop scaleFactor:(CGFloat)scaleFactor
    {
        // Rotating halfway (pi radians) around the Y axis gives the appearance of flipping
        CABasicAnimation *flipAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
        CGFloat startValue = beginsOnTop ? 0.0f : M_PI/2;
        CGFloat endValue = beginsOnTop ? -M_PI/2 : 0.0f;
        flipAnimation.fromValue = [NSNumber numberWithDouble:startValue];
        flipAnimation.toValue = [NSNumber numberWithDouble:endValue];
    
        // Shrinking the view makes it seem to move away from us, for a more natural effect
        // Can also grow the view to make it move out of the screen
        CABasicAnimation *shrinkAnimation = nil;
        if (scaleFactor != 1.0 ) {
            shrinkAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
            shrinkAnimation.toValue = [NSNumber numberWithFloat:scaleFactor];
    
            // We only have to animate the shrink in one direction, then use autoreverse to "grow"
            shrinkAnimation.duration = aDuration * 0.5;
            shrinkAnimation.autoreverses = YES;
        }
    
        // Combine the flipping and shrinking into one smooth animation
        CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
        animationGroup.animations = [NSArray arrayWithObjects:flipAnimation, shrinkAnimation, nil];
    
        // As the edge gets closer to us, it appears to move faster. Simulate this in 2D with an easing function
        animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:beginsOnTop?kCAMediaTimingFunctionEaseIn:kCAMediaTimingFunctionEaseOut];
        animationGroup.duration = aDuration;
    
        // this really means keep the state of the object at whatever the anim ends at
        // if you don't do this then it reverts back to the original state (e.g. brown layer)
        animationGroup.fillMode = kCAFillModeForwards;
        animationGroup.removedOnCompletion = NO;
    
        return animationGroup;
    }
    

    The two views are named primaryView and secondaryView. You can use any view, (ImageView, text view...)