Я делаю нечто очень похожее в одном из моих проектов с сеткой обложек альбомов.
Это подход, который я использую. Ключ должен использовать CAAnimationGroup
.
1) Вся анимация будет включать в себя масштабирование, вращение и перемещение по пути одновременно - сначала для слоя обложки альбома, а затем для слоя модального вида.
2) Анимируйте слой обложки альбома, перевернув его на 90 градусов, немного масштабировав и перейдя в предопределенное место из его текущего местоположения. В этот момент он исчезнет (вертикально к экрану).
3) Добавьте модальное представление. Масштабируйте и трансформируйте модальное представление так, чтобы оно было точно в том месте, в котором обложка альбома расположена на шаге 1.
4) Анимация модального вида из этой позиции путем масштабирования, поворота и перемещения по траектории для заполнения экрана.
5) Удалить модальное представление.
6) Представлен модальный вид без анимации.
7) Выбранный путь обычно добавляет центр экрана в качестве контрольной точки. Но тогда это можно изменить в зависимости от того, как вы хотите, чтобы анимация отображалась.
Ниже приведена функция, где вы можете увидеть использование анимационной группы. Надеюсь, это поможет вам. Я до сих пор не понял, как избежать отсечения анимации с помощью панелей навигации и панелей вкладок. :)
+ (void)animateWithCurrentView:(UIView *)currentView
{
#define kResizeKey @"bounds.size"
#define kPathMovement @"position"
#define kRotation @"transform"
#define kGroupAnimation @"subviewBeingAnimated"
#define kLayerAnimation @"animateLayer"
//flip the view by 180 degrees in its place first.
currentView.layer.transform = CATransform3DRotate(currentView.layer.transform,radians(180), 0, 1, 0);
//set the anchor point so that the view rotates on one of its sides.
currentView.layer.anchorPoint = CGPointMake(0.0, 0.5);
/**
* Set up scaling
*/
CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:kResizeKey];
//we are going to fill the screen here. So 320,480
[resizeAnimation setToValue:[NSValue valueWithCGSize:CGSizeMake(320, 480)]];
resizeAnimation.fillMode = kCAFillModeForwards;
resizeAnimation.removedOnCompletion = NO;
/**
* Set up path movement
*/
UIBezierPath *movePath = [UIBezierPath bezierPath];
//the control point is now set to centre of the filled screen. Change this to make the path different.
CGPoint ctlPoint = CGPointMake(160.0, 240.0);
//This is the starting point of the animation. This should ideally be a function of the frame of the view to be animated. Hardcoded here.
[movePath moveToPoint:CGPointMake(320, 60)];
//The anchor point is going to end up here at the end of the animation.
[movePath addQuadCurveToPoint:CGPointMake(0, 240) controlPoint:ctlPoint];
CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:kPathMovement];
moveAnim.path = movePath.CGPath;
moveAnim.removedOnCompletion = YES;
/**
* Setup rotation animation
*/
CABasicAnimation* rotateAnimation = [CABasicAnimation animationWithKeyPath:kRotation];
//start from 180 degrees (done in 1st line)
CATransform3D fromTransform = CATransform3DMakeRotation(radians(180), 0, 1, 0);
//come back to 0 degrees
CATransform3D toTransform = CATransform3DMakeRotation(radians(0), 0, 1, 0);
//This is done to get some perspective.
CATransform3D persp1 = CATransform3DIdentity;
persp1.m34 = 1.0 / -3000;
fromTransform = CATransform3DConcat(fromTransform, persp1);
toTransform = CATransform3DConcat(toTransform,persp1);
rotateAnimation.toValue = [NSValue valueWithCATransform3D:toTransform];
rotateAnimation.fromValue = [NSValue valueWithCATransform3D:fromTransform];
//rotateAnimation.duration = 2;
rotateAnimation.fillMode = kCAFillModeForwards;
rotateAnimation.removedOnCompletion = NO;
/**
* Setup and add all animations to the group
*/
CAAnimationGroup *group = [CAAnimationGroup animation];
[group setAnimations:[NSArray arrayWithObjects:moveAnim,rotateAnimation, resizeAnimation, nil]];
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
group.duration = 0.7f;
group.delegate = self;
[group setValue:currentView forKey:kGroupAnimation];
/**
* ...and go
*/
[currentView.layer addAnimation:group forKey:kLayerAnimation];
}