扩展视图控制器之间的圆形动画过渡

Yar*_*neo 2 uiviewanimation uiviewanimationtransition ios

我使用转换委托创建了自定义动画转换:

vc.modalTransitionStyle = UIModalPresentationCustom;
vc.transitioningDelegate = self.transitioningDelegate;
Run Code Online (Sandbox Code Playgroud)

过渡代表工作得很好,但我试图达到迄今为止我没有成功的效果.我试图让新的视图控制器看起来像这样的效果:

很酷的动画tranisitoning

我尝试过做CGAffineTransformMakeScale,但是它会缩放新的视图控制器视图,而不仅仅是"将视图圈扩展到它".当尝试使用动画更改边界和边框时,它总是最适合圆圈与屏幕边界,并且不会像我给出的动画那样完全打开圆圈.

有任何想法吗?

谢谢.

rde*_*mar 14

我对这个问题的第一个答案是我刚刚发布的应用程序的修改版本,现在不是最好的方法(iOS 7及更高版本).在iOS 7中,我们可以使用UIViewControllerTransitioningDelegate和相关的委托和类创建自定义转换.此版本封装了动画对象(符合UIViewControllerAnimatedTransitioning的对象)中的所有蒙版创建和大小调整,因此它使控制器代码更简单,允许您使用任何控制器作为目标控制器而无需特殊代码.这是我在进行演示的类中使用的代码,

#import "ViewController.h"
#import "SecondViewController.h"
#import "RDPresentationAnimator.h"

@interface ViewController () <UIViewControllerTransitioningDelegate>
@property (weak,nonatomic) IBOutlet UIButton *button;
@end

@implementation ViewController

-(IBAction)presentSecondController:(UIButton *)sender {
    self.button = sender;
    SecondViewController *second = [self.storyboard instantiateViewControllerWithIdentifier:@"Second"];
    second.modalTransitionStyle = UIModalPresentationCustom;
    second.transitioningDelegate = self;
    [self presentViewController:second animated:YES completion:nil];
}

-(id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
    RDPresentationAnimator *animator = [RDPresentationAnimator new];
    animator.isPresenting = YES;
    animator.senderFrame = self.button.frame;
    return animator;
}


-(id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    NSLog(@"dismissed delegate called");
    RDPresentationAnimator *animator = [RDPresentationAnimator new];
    animator.isPresenting = NO;
    animator.senderFrame = self.button.frame;
    return animator;
}
Run Code Online (Sandbox Code Playgroud)

这是动画师对象中的代码..h,

@interface RDPresentationAnimator : NSObject <UIViewControllerAnimatedTransitioning>

@property (nonatomic) BOOL isPresenting;
@property (nonatomic) CGRect senderFrame;
Run Code Online (Sandbox Code Playgroud)

这是.m,

@interface RDPresentationAnimator ()
@property (strong,nonatomic) UIBezierPath *maskPath;
@property (strong,nonatomic) UIViewController *toVC;
@property (strong,nonatomic) UIViewController *fromVC;
//@property (strong,nonatomic) id <UIViewControllerContextTransitioning> transitionContext;
@end

    @implementation RDPresentationAnimator

    #define ANIMATION_TIME 0.6



    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
        return ANIMATION_TIME;
    }


    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
       // self.transitionContext = transitionContext;
        self.fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        self.toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

        if (self.isPresenting) {
            [transitionContext.containerView addSubview:self.fromVC.view];
            [transitionContext.containerView addSubview:self.toVC.view];

            self.maskPath = [UIBezierPath bezierPathWithOvalInRect:self.senderFrame];
            CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
            maskLayer.frame = self.toVC.view.frame;
            maskLayer.path = self.maskPath.CGPath;
            self.toVC.view.layer.mask = maskLayer;

            UIBezierPath *newPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-self.toVC.view.frame.size.width/2, -self.toVC.view.frame.size.height/2, self.toVC.view.frame.size.height*2, self.toVC.view.frame.size.height*2)];
            CABasicAnimation* pathAnim = [CABasicAnimation animationWithKeyPath: @"path"];
            //pathAnim.delegate = self;
            pathAnim.fromValue = (id)self.maskPath.CGPath;
            pathAnim.toValue = (id)newPath.CGPath;
            pathAnim.duration = ANIMATION_TIME;
            maskLayer.path = newPath.CGPath;
            [maskLayer addAnimation:pathAnim forKey:@"path"];
        }else{
            [transitionContext.containerView addSubview:self.toVC.view];
            [transitionContext.containerView addSubview:self.fromVC.view];
            self.maskPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-self.fromVC.view.frame.size.width/2, -self.fromVC.view.frame.size.height/2, self.fromVC.view.frame.size.height*2, self.fromVC.view.frame.size.height*2)];
            CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
            maskLayer.frame = self.fromVC.view.frame;
            maskLayer.path = self.maskPath.CGPath;
            self.fromVC.view.layer.mask = maskLayer;

            UIBezierPath *newPath = [UIBezierPath bezierPathWithOvalInRect:self.senderFrame];
            CABasicAnimation* pathAnim = [CABasicAnimation animationWithKeyPath: @"path"];
            //pathAnim.delegate = self;
            pathAnim.fromValue = (id)self.maskPath.CGPath;
            pathAnim.toValue = (id)newPath.CGPath;
            pathAnim.duration = ANIMATION_TIME;
            maskLayer.path = newPath.CGPath;
            [maskLayer addAnimation:pathAnim forKey:@"path"];
        }

        [self performSelector:@selector(finishTransition:) withObject:transitionContext afterDelay:ANIMATION_TIME];
    }



    -(void)finishTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
        [transitionContext completeTransition:YES];
    }


    //- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
    //    NSLog(@"In didStop");
    //    if (flag) {
    //        if (self.isPresenting) {
    //            self.toVC.view.layer.mask = nil;
    //            [self.transitionContext completeTransition:YES];
    //        }else{
    //            self.fromVC.view.layer.mask = nil;
    //            [self.transitionContext completeTransition:YES];
    //            self.transitionContext = nil;
    //        }
    //    }
    //}


    -(void)dealloc {
        NSLog(@"In animator dealloc");
    }
Run Code Online (Sandbox Code Playgroud)

当您解雇模态控制器时,此代码也具有反向动画(您只需要调用dismissViewControllerAnimated:completion:与该类中的正常一样).

  • 谢谢你的样品,它工作得很好.我会编辑答案,因为在容器视图中为VC和toVC的每一步添加,它会产生问题,因为容器在完成后释放,我删除了addSubview,只有这是必要的[transitionContext.containerView addSubview:self.toVC .视图]; 它解决了黑屏的问题. (2认同)