我对这个问题的第一个答案是我不久前制作的应用程序的修改版本,现在不是最好的方法(iOS 7 及更高版本)。在 iOS 7 中,我们可以使用 UIViewControllerTransitioningDelegate 以及相关的委托和类来创建自定义转换。此版本将所有蒙版创建和调整大小封装在 animator 对象(符合 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;
}
这是动画对象中的代码。 .h,
@interface RDPresentationAnimator : NSObject <UIViewControllerAnimatedTransitioning>
@property (nonatomic) BOOL isPresenting;
@property (nonatomic) CGRect senderFrame;
这是.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");
}
当您关闭模态控制器时,此代码还具有反向动画(您只需像在该类中一样调用dismissViewControllerAnimated:completion:)。