自定義轉場動畫步驟:bash
自定義動畫的主要代碼都在管理類中實現,在須要動畫的時候調用這個類的方法便可。動畫
ZZFTransition.hui
#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, ZZFTransitionType) { ZZFTransitionTypePush, ZZFTransitionTypePop,};
@interface ZZFTransition : NSObject<UIViewControllerAnimatedTransitioning,CAAnimationDelegate>+(ZZFTransition *)transitionAnimationWithType:(ZZFTransitionType)type;@end複製代碼
定義枚舉類型ZZFTransitionType,包含兩個值,分別是push類型和pop類型。spa
定義類方法transitionAnimationWithType,傳入動畫類型,返回實例對象。代理
ZZFTransition.mcode
+(ZZFTransition *)transitionAnimationWithType:(ZZFTransitionType)type{
ZZFTransition *transition = [[ZZFTransition alloc]init];
transition.type = type;
return transition;
}
複製代碼
在.m文件中實現transitionAnimationWithType類方法,初始化實例對象,設置動畫類型,返回對象。cdn
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
return 3;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
self.transitionContext = transitionContext;
switch (_type) {
case ZZFTransitionTypePush:
{
[self pushAnimation:transitionContext];
}
break;
case ZZFTransitionTypePop:
{
[self popAnimation:transitionContext];
}
break;
}
}
複製代碼
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext;這個方法返回轉場動畫執行的時間。對象
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext;在這個方法內部實現動畫的主要代碼。開發
這裏根據建立管理對象的時候傳進來的動畫類型,來分別處理不一樣的動畫邏輯。把push和pop的動畫實現放到一個方法中去,這裏的代碼更簡潔。animation
- (void)pushAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
// 得到即將消失的vc的v
UIView *fromeView = [transitionContext viewForKey:UITransitionContextFromViewKey];
// 得到即將出現的vc的v
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
// 得到容器view
UIView *containerView = [transitionContext containerView];
[containerView addSubview:fromeView];
[containerView addSubview:toView];
UIBezierPath *startBP = [UIBezierPath bezierPathWithOvalInRect:CGRectMake((containerView.frame.size.width)/2, (containerView.frame.size.height)/2, 12, 12)];
CGFloat radius = containerView.frame.size.height - 100;
UIBezierPath *finalBP = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(150 - radius, 150 -radius, radius*2, radius*2)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = finalBP.CGPath;
toView.layer.mask = maskLayer;
//執行動畫
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
animation.fromValue = (__bridge id _Nullable)(startBP.CGPath);
animation.toValue = (__bridge id _Nullable)(finalBP.CGPath);
animation.duration = [self transitionDuration:transitionContext];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.delegate = self;
[maskLayer addAnimation:animation forKey:@"path"];
}
複製代碼
參數transitionContext是執行動畫的上下文,裏面包含動畫執行所須要的全部元素。
經過鍵值的方式,從上下文對象中能夠的到須要執行動畫的上一個VC和view,下一個VC和view。
UITransitionContextFromViewKey 即將消失的view
UITransitionContextToViewKey 即將出現的view
UITransitionContextFromViewControllerKey 即將消失的控制器
UITransitionContextToViewControllerKey 即將出現的控制器
而後經過上下文的containerView方法能夠獲得一個容器view,全部的動畫都是在這個容器view內進行的,因此須要把fromView和toView都加入到containerView中。
下邊用貝塞爾曲線畫兩個圓,而後用CABasicAnimation執行從小圓到大圓的動畫。
到這裏一個自定義的push動畫就完成了,下邊是使用的方法。
在須要執行自定義動畫的控制器中,遵照UINavigationControllerDelegate協議,並實現-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC;代理方法。
在執行push或pop操做時,這個代理方法會回調,在方法內部拿到跳轉的動畫類型,而後執行本身的動畫代碼就能夠實現自定義轉場動畫。
-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{
if (operation == UINavigationControllerOperationPush) {
ZZFTransition *pushTranstion = [ZZFTransition transitionAnimationWithType:ZZFTransitionTypePush];
return pushTranstion;
}
return nil;
}
複製代碼
這裏只實現了push,要實現pop自定義動畫,同理。
執行push動畫後,能夠發現一個問題,界面的全部交互失效了,是由於執行動畫時控制器view上加了遮罩layer,在動畫執行完成後把遮罩去掉就能夠了。
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
[self.transitionContext completeTransition:YES];
//清除相應控制器視圖的mask
[self.transitionContext viewForKey:UITransitionContextFromViewKey].layer.mask = nil;
[self.transitionContext viewForKey:UITransitionContextToViewKey].layer.mask = nil;
}
複製代碼