我使用过渡委托创建了自定义动画过渡:
vc.modalTransitionStyle = UIModalPresentationCustom;
vc.transitioningDelegate = self.transitioningDelegate;
转换代表工作正常,但我正在努力实现迄今为止我没有成功完成的效果。 我试图使新的视图控制器看起来像这样的效果:
我尝试过做CGAffineTransformMakeScale,但它放大了新的视图控制器视图,而不仅仅是“将视图圈扩展到它”。当尝试使用动画更改边界和边框时,它总是最适合圆圈与屏幕边界,并且不像我给出的动画那样完全打开圆圈。
有什么想法吗?
感谢。
答案 0 :(得分: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;
}
这里是动画对象中的代码。 .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:就像那个类中的正常一样)。
答案 1 :(得分:3)
我过去曾经做过类似的事情,但它并没有那种扩大的橙色戒指。我的InitialViewController在故事板中添加了一个带有圆形蒙版和背景图像的按钮。我提供的视图控制器有一个掩码,其大小和位置是通过传入触发演示的InitialViewController中按钮的框架来设置的。呈现的视图控制器定义一个协议,其一个方法在动画结束时被调用。这是初始视图控制器中的代码,
#import "InitialViewController.h"
#import "ViewController.h"
@interface InitialViewController () <ExpandingViewDelegate>
@end
@implementation InitialViewController
-(IBAction)expandToDetail:(UIButton *)sender {
ViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"VC"];
vc.delegate = self;
vc.buttonRect = sender.frame;
[self.view addSubview:vc.view];
}
-(void)viewFinishedAnimating:(UIViewController *) sender { // delegate method from the presentedViewController
[sender.view removeFromSuperview];
[self presentViewController:sender animated:NO completion:nil];
}
这是所呈现的视图控制器中的代码,它执行掩码扩展。 .h文件,
@protocol ExpandingViewDelegate <NSObject>
-(void)viewFinishedAnimating:(UIViewController *) sender;
@end
@interface ViewController : UIViewController
@property (nonatomic) CGRect buttonRect;
@property (weak,nonatomic) id<ExpandingViewDelegate> delegate;
@end
.m文件,
@interface ViewController ()
@property (strong,nonatomic) UIBezierPath *maskPath;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.maskPath = [UIBezierPath bezierPathWithOvalInRect:self.buttonRect];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.view.frame;
maskLayer.path = self.maskPath.CGPath;
self.view.layer.mask = maskLayer;
[self enlargeMask:maskLayer];
}
-(void)enlargeMask:(CAShapeLayer *) shapeLayer {
UIBezierPath *newPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-self.view.frame.size.width/2, -self.view.frame.size.height/2, self.view.frame.size.height*2, self.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 = 6;
shapeLayer.path = newPath.CGPath;
[shapeLayer addAnimation:pathAnim forKey:@"path"];
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
if (flag) {
self.view.layer.mask = nil;
[self.delegate viewFinishedAnimating:self];
}
}