Skip to content

Commit 6d03387

Browse files
committed
Fixed shadow and rounded corner rotation animations.
1 parent 6320d51 commit 6d03387

File tree

1 file changed

+140
-61
lines changed

1 file changed

+140
-61
lines changed

ViewDeck/IIViewDeckController.m

+140-61
Original file line numberDiff line numberDiff line change
@@ -923,8 +923,8 @@ - (void)viewWillAppear:(BOOL)animated {
923923
controller.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
924924
}];
925925

926+
[self applyCenterViewCornerRadiusAnimated:NO];
926927
[self applyShadowToSlidingViewAnimated:NO];
927-
[self applyCenterViewCornerRadius];
928928
[self applyCenterViewOpacityIfNeeded];
929929
};
930930

@@ -1051,40 +1051,13 @@ - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInte
10511051
[controller willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
10521052
}];
10531053

1054-
CABasicAnimation* anim = nil;
1055-
// only animate shadow if we've applied it ourselves.
1056-
if ([self.delegate respondsToSelector:@selector(viewDeckController:applyShadow:withBounds:)]) {
1057-
for (NSString* key in self.slidingControllerView.layer.animationKeys) {
1058-
if ([key isEqualToString:@"bounds"]) {
1059-
CABasicAnimation* other = (CABasicAnimation*)[self.slidingControllerView.layer animationForKey:key];
1060-
1061-
if ([other isKindOfClass:[CABasicAnimation class]]) {
1062-
anim = [CABasicAnimation animationWithKeyPath:@"shadowPath"];
1063-
anim.fromValue = (__bridge id)[UIBezierPath bezierPathWithRect:[other.fromValue CGRectValue]].CGPath;
1064-
anim.duration = other.duration;
1065-
anim.timingFunction = other.timingFunction;
1066-
break;
1067-
}
1068-
}
1069-
}
1070-
}
1071-
1072-
// fallback: make shadow transparent and fade in to desired value. This gives the same visual
1073-
// effect as animating
1074-
if (!anim) {
1075-
anim = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
1076-
anim.fromValue = @(0.0);
1077-
anim.duration = 1;
1078-
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
1079-
}
1080-
[self.slidingControllerView.layer addAnimation:anim forKey:@"shadowOpacity"];
1081-
1054+
[self applyCenterViewCornerRadiusAnimated:YES];
1055+
[self applyShadowToSlidingViewAnimated:YES];
10821056
}
10831057

10841058

10851059
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
10861060
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
1087-
[self restoreShadowToSlidingView];
10881061

10891062
if (_preRotationSize.width == 0) {
10901063
_preRotationSize = self.referenceBounds.size;
@@ -1099,7 +1072,6 @@ - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrie
10991072

11001073
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
11011074
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
1102-
[self applyShadowToSlidingViewAnimated:YES];
11031075

11041076
[self relayRotationMethod:^(UIViewController *controller) {
11051077
[controller didRotateFromInterfaceOrientation:fromInterfaceOrientation];
@@ -3105,7 +3077,7 @@ - (void)setCenterController:(UIViewController *)centerController {
31053077

31063078
[_centerController view]; // make sure the view is loaded before calling viewWillAppear:
31073079
[self applyCenterViewOpacityIfNeeded];
3108-
[self applyCenterViewCornerRadius];
3080+
[self applyCenterViewCornerRadiusAnimated:NO];
31093081
afterBlock(_centerController);
31103082
[_centerController didMoveToParentViewController:self];
31113083

@@ -3281,35 +3253,90 @@ - (void)applyCenterViewOpacityIfNeeded {
32813253

32823254
- (void)setCenterViewCornerRadius:(CGFloat)centerViewCornerRadius {
32833255
_centerViewCornerRadius = centerViewCornerRadius;
3284-
[self applyCenterViewCornerRadius];
3256+
[self applyCenterViewCornerRadiusAnimated:NO];
32853257
}
32863258

3287-
- (void)applyCenterViewCornerRadius {
3259+
- (UIBezierPath*)generateCenterViewCornerRadiusPath {
3260+
CGRect rect = self.slidingControllerView.layer.bounds;
32883261
if (_centerViewCornerRadius == 0)
3289-
self.slidingControllerView.layer.mask = nil;
3290-
else {
3291-
// create mask path
3292-
CGRect rect = self.slidingControllerView.layer.bounds;
3293-
CGSize radius = (CGSize) { _centerViewCornerRadius, _centerViewCornerRadius };
3294-
UIRectCorner corners = 0;
3295-
if (self.leftController)
3296-
corners |= UIRectCornerTopLeft | UIRectCornerBottomLeft;
3297-
if (self.rightController)
3298-
corners |= UIRectCornerTopRight | UIRectCornerBottomRight;
3299-
if (self.topController)
3300-
corners |= UIRectCornerTopLeft | UIRectCornerTopRight;
3301-
if (self.bottomController)
3302-
corners |= UIRectCornerBottomLeft | UIRectCornerBottomRight;
3303-
UIBezierPath* path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corners cornerRadii:radius];
3304-
3305-
CAShapeLayer* mask = [CAShapeLayer layer];
3306-
mask.path = [path CGPath];
3307-
mask.frame = rect;
3308-
self.slidingControllerView.layer.mask = mask;
3309-
// also update shadow layer
3310-
_shadowLayer.shadowPath = [path CGPath];
3311-
}
3262+
return [UIBezierPath bezierPathWithRect:rect];
33123263

3264+
// create mask path
3265+
CGSize radius = (CGSize) { _centerViewCornerRadius, _centerViewCornerRadius };
3266+
UIRectCorner corners = 0;
3267+
if (self.leftController)
3268+
corners |= UIRectCornerTopLeft | UIRectCornerBottomLeft;
3269+
if (self.rightController)
3270+
corners |= UIRectCornerTopRight | UIRectCornerBottomRight;
3271+
if (self.topController)
3272+
corners |= UIRectCornerTopLeft | UIRectCornerTopRight;
3273+
if (self.bottomController)
3274+
corners |= UIRectCornerBottomLeft | UIRectCornerBottomRight;
3275+
UIBezierPath* path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corners cornerRadii:radius];
3276+
3277+
return path;
3278+
}
3279+
3280+
- (void)applyCenterViewCornerRadiusAnimated:(BOOL)animated {
3281+
UIBezierPath* path = [self generateCenterViewCornerRadiusPath];
3282+
3283+
if (!self.slidingControllerView.layer.mask) {
3284+
self.slidingControllerView.layer.mask = [CAShapeLayer layer];
3285+
((CAShapeLayer*)self.slidingControllerView.layer.mask).path = [path CGPath];
3286+
}
3287+
3288+
CAShapeLayer* mask = (CAShapeLayer*)self.slidingControllerView.layer.mask;
3289+
if (animated) {
3290+
CGFloat duration = 0.3;
3291+
CAMediaTimingFunction* timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
3292+
[self currentAnimationDuration:&duration timingFunction:&timingFunction];
3293+
3294+
CABasicAnimation* anim;
3295+
anim = [CABasicAnimation animationWithKeyPath:@"bounds"];
3296+
anim.duration = duration;
3297+
anim.timingFunction = timingFunction;
3298+
anim.fromValue = [NSValue valueWithCGRect:mask.bounds];
3299+
anim.toValue = [NSValue valueWithCGRect:[path bounds]];
3300+
anim.fillMode = kCAFillModeForwards;
3301+
[mask addAnimation:anim forKey:@"animateBounds"];
3302+
3303+
anim = [CABasicAnimation animationWithKeyPath:@"path"];
3304+
anim.duration = duration;
3305+
anim.timingFunction = timingFunction;
3306+
anim.fromValue = (id)mask.path;
3307+
anim.toValue = (id)[path CGPath];
3308+
anim.fillMode = kCAFillModeForwards;
3309+
[mask addAnimation:anim forKey:@"animatePath"];
3310+
3311+
anim = [CABasicAnimation animationWithKeyPath:@"position"];
3312+
anim.duration = duration;
3313+
anim.timingFunction = timingFunction;
3314+
anim.fromValue = [NSValue valueWithCGPoint:_shadowLayer.position];
3315+
anim.toValue = [NSValue valueWithCGPoint:self.slidingControllerView.layer.position];
3316+
anim.fillMode = kCAFillModeForwards;
3317+
[_shadowLayer addAnimation:anim forKey:@"animatePosition"];
3318+
3319+
anim = [CABasicAnimation animationWithKeyPath:@"bounds"];
3320+
anim.duration = duration;
3321+
anim.timingFunction = timingFunction;
3322+
anim.fromValue = [NSValue valueWithCGRect:_shadowLayer.bounds];
3323+
anim.toValue = [NSValue valueWithCGRect:self.slidingControllerView.layer.bounds];
3324+
anim.fillMode = kCAFillModeForwards;
3325+
[_shadowLayer addAnimation:anim forKey:@"animateBounds"];
3326+
3327+
anim = [CABasicAnimation animationWithKeyPath:@"shadowPath"];
3328+
anim.duration = duration;
3329+
anim.timingFunction = timingFunction;
3330+
anim.fromValue = (id)_shadowLayer.shadowPath;
3331+
anim.toValue = (id)[path CGPath];
3332+
anim.fillMode = kCAFillModeForwards;
3333+
[_shadowLayer addAnimation:anim forKey:@"animateShadowPath"];
3334+
}
3335+
3336+
mask.path = [path CGPath];
3337+
mask.frame = [path bounds];
3338+
_shadowLayer.shadowPath = [path CGPath];
3339+
_shadowLayer.frame = self.slidingControllerView.layer.frame;
33133340
}
33143341

33153342
#pragma mark - Shadow
@@ -3344,13 +3371,65 @@ - (void)applyShadowToSlidingViewAnimated:(BOOL)animated {
33443371
[self.delegate viewDeckController:self applyShadow:_shadowLayer withBounds:self.referenceBounds];
33453372
}
33463373
else {
3347-
[shadowedView.layer.superlayer insertSublayer:_shadowLayer below:shadowedView.layer];
3348-
_shadowLayer.frame = shadowedView.layer.frame;
3349-
_shadowLayer.shadowPath = shadowedView.layer.mask ? ((CAShapeLayer*)shadowedView.layer.mask).path : [[UIBezierPath bezierPathWithRect:shadowedView.bounds] CGPath];
3374+
CGPathRef newPath = ((CAShapeLayer*)self.slidingControllerView.layer.mask).path;
3375+
if (animated) {
3376+
CGFloat duration;
3377+
CAMediaTimingFunction* timingFunction;
3378+
if ([self currentAnimationDuration:&duration timingFunction:&timingFunction]) {
3379+
CABasicAnimation* anim;
3380+
if (![_shadowLayer animationForKey:@"animateShadowPath"]) {
3381+
anim = [CABasicAnimation animationWithKeyPath:@"shadowPath"];
3382+
anim.fromValue = (id)_shadowLayer.shadowPath;
3383+
anim.toValue = (__bridge id)newPath;
3384+
anim.duration = duration;
3385+
anim.timingFunction = timingFunction;
3386+
anim.fillMode = kCAFillModeForwards;
3387+
[_shadowLayer addAnimation:anim forKey:@"animateShadowPath"];
3388+
3389+
anim = [CABasicAnimation animationWithKeyPath:@"bounds"];
3390+
anim.duration = duration;
3391+
anim.timingFunction = timingFunction;
3392+
anim.fromValue = [NSValue valueWithCGRect:_shadowLayer.bounds];
3393+
anim.toValue = [NSValue valueWithCGRect:self.slidingControllerView.layer.bounds];
3394+
anim.fillMode = kCAFillModeForwards;
3395+
[_shadowLayer addAnimation:anim forKey:@"animateBounds"];
3396+
}
3397+
}
3398+
3399+
// fallback: make shadow transparent and fade in to desired value. This gives the same visual
3400+
// effect as animating
3401+
if ([_shadowLayer animationKeys].count == 0) {
3402+
CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
3403+
anim.fromValue = @(0.0);
3404+
anim.duration = 1;
3405+
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
3406+
anim.fillMode = kCAFillModeForwards;
3407+
[_shadowLayer addAnimation:anim forKey:@"animateShadowOpacity"];
3408+
}
3409+
}
3410+
else {
3411+
[shadowedView.layer.superlayer insertSublayer:_shadowLayer below:shadowedView.layer];
3412+
_shadowLayer.frame = shadowedView.layer.frame;
3413+
_shadowLayer.shadowPath = newPath;
3414+
}
33503415
}
33513416
}
33523417

3353-
3418+
- (BOOL)currentAnimationDuration:(CGFloat*)duration timingFunction:(CAMediaTimingFunction**)timingFunction {
3419+
for (NSString* key in self.slidingControllerView.layer.animationKeys) {
3420+
if ([key isEqualToString:@"bounds"]) {
3421+
CABasicAnimation* other = (CABasicAnimation*)[self.slidingControllerView.layer animationForKey:key];
3422+
3423+
if ([other isKindOfClass:[CABasicAnimation class]]) {
3424+
*duration = other.duration;
3425+
*timingFunction = other.timingFunction;
3426+
return YES;
3427+
}
3428+
}
3429+
}
3430+
3431+
return NO;
3432+
}
33543433
@end
33553434

33563435
#pragma mark -

0 commit comments

Comments
 (0)