How do you flip non-fullscreen UIView's in a s

2019-04-01 22:19发布

I'm flipping UIViews similar to the page flip of the Weather app. The views are not fullscreen, though, and the superview has rounded corners. The problem is that during the flip animation the rounded corners of the superview are filled out to the square corners with black.

Here's how I'm setting the corners:

self.view.layer.cornerRadius = 15.0f;
self.view.clipsToBounds = YES;

Here's how I'm flipping the views (both frontView and backView are retained):

UIView *toView;
UIView *fromView;
UIViewAnimationOptions animationType;

if (toFront) {
    toView = self.frontView;
    fromView = self.backView;
    animationType = UIViewAnimationOptionTransitionFlipFromLeft;
} else {
    toView = self.backView;
    fromView = self.frontView;
    animationType = UIViewAnimationOptionTransitionFlipFromRight;
}

[UIView transitionFromView:self.fromView
                    toView:self.toView
                  duration:1
                   options:animationType
                completion:nil];

When I do this, self.view's round corners are filled out to their rectangular corner edges with black. Can this be avoided? I don't think I know enough about Core Animation to solve this.

2条回答
ら.Afraid
2楼-- · 2019-04-01 22:46

Here's what I ended up writing. Seems to work fine, but, of course, test it yourself.

Things to note:

  • You should add the view you are animating TO before calling this method.

  • The method does NOT remove any of the views, so remove them with the completion block if necessary.

  • The method also does not modify the 'layer model' values of your views, so they will stay the same as they were after the animation.

`

+ (void)flipRight:(BOOL)flipRight fromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration completion:(void (^)(void))completionBlock {

// Save original values
BOOL fromViewDoubleSided = fromView.layer.doubleSided;
BOOL toViewDoubleSided = toView.layer.doubleSided;
BOOL fromViewUserInteractionEnabled = fromView.userInteractionEnabled;
BOOL toViewUserInteractionEnabled = toView.userInteractionEnabled;

// We don't want to see the other side of the layer
fromView.layer.doubleSided = NO;
toView.layer.doubleSided = NO;

// We don't want user to fire off animation while its already going
fromView.userInteractionEnabled = NO;
toView.userInteractionEnabled = NO;

[CATransaction begin];

[CATransaction setCompletionBlock:^{

    // Restore original values
    fromView.layer.doubleSided = fromViewDoubleSided;
    toView.layer.doubleSided = toViewDoubleSided;
    fromView.userInteractionEnabled = fromViewUserInteractionEnabled;
    toView.userInteractionEnabled = toViewUserInteractionEnabled;

    if (completionBlock) completionBlock();
}];

CATransform3D flipOutTransform3D = CATransform3DMakeRotation(M_PI, 0,1,0);
flipOutTransform3D.m34 = 1.0/(300.0*(flipRight ? -1 : 1));
CABasicAnimation *flipOutAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
flipOutAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
flipOutAnimation.toValue = [NSValue valueWithCATransform3D:flipOutTransform3D];
flipOutAnimation.duration = duration;

CATransform3D flipInTransform3D = CATransform3DMakeRotation(M_PI, 0,1,0);
flipInTransform3D.m34 = 1.0/(300.0*(flipRight ? 1 : -1));
CABasicAnimation *flipInAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
flipInAnimation.fromValue = [NSValue valueWithCATransform3D:flipInTransform3D];
flipInAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
flipInAnimation.duration = duration;


[fromView.layer addAnimation:flipOutAnimation forKey:@"flipOutAnimation"];
[toView.layer addAnimation:flipInAnimation forKey:@"flipInAnimation"];

[CATransaction commit];
};
查看更多
叼着烟拽天下
3楼-- · 2019-04-01 22:54

If you need to do this in Core Animation, you would do it by making the animation separately from replacing the views. It's not impossibly difficult. The description of how to do it and some sample code is below:

Replacing the views

Replacing the views can for example be done using:

[UIView transitionFromView:self.fromView
                    toView:self.toView
                  duration:0.0
                   options:UIViewAnimationOptionTransitionNone
                completion:nil];

Animating the flip

The difficult part is obviously the animation (and putting both together if you've never done it before).

Only showing the front of both views

Since you want to flip the two views as if they are two sides of a piece of paper you don't want either of them to appear when they are facing away. This is done by setting the doubleSided property to NO on both layers. (not being double sided means being single sided).

Making the flip

You want to animate the transform of the front view from a identity transform (no transform) to a 180 degree rotated transform (facing backwards) around the y-axis so that it flips form left to right.

At the same time you want to animate the transform of the back view from a -180 degree rotation to an identity transform. This will make flip back. Both of these animations can be done as "basic" animations:

CABasicAnimation *flipAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
[flipAnimation setFromValue:[NSValue valueWithCATransform3D:CATransform3DIdentity]]; // No rotation
[flipAnimation setToValue:[NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 0,1,0)]]; // Rotate PI around Y
[flipAnimation setFillMode:kCAFillModeBoth];
[flipAnimation setRemoveOnCompletion:NO];
[flippingView layer] addAnimation:flipAnimation forKey:@"myFlipAnimation"];

You then do the same kind of animation for the other view. (The fill mode prevents the animation from jumping back to its original state after completion)

Putting it all together

Since you want both animations to run at the same time and want your view-replacing code to run when the animation finishes you can use a animation transaction. This will also allow you to configure how both animations look at one place:

[CATransaction begin];
[CATransaction setAnimationDuration:2.0]; // 2 seconds
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[CATransaction setCompletionBlock:^{
    // Your view replacing code here...
}];
// Add the animations to both views here...
[CATransaction commit];
查看更多
登录 后发表回答