iOS自定義轉場動畫
iOS7推出了新的轉場動畫API,以協議id<UIViewControllerInterativeTransition>、id<UIViewAnimatedTransitioning>方式開放給開發者,不同於代理、類別,這樣更易於我們自定義動畫,更加靈活。下面介紹一下自定義轉場動畫
自定義轉場動畫步驟:
1:建立動畫管理類ZZFTransition,實現UIViewControllerAnimatedTransitioning,CAAnimationDelegate協議
自定義動畫的主要程式碼都在管理類中實現,在需要動畫的時候呼叫這個類的方法即可。
ZZFTransition.h
#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型別。
定義類方法transitionAnimationWithType,傳入動畫型別,返回例項物件。
ZZFTransition.m
+(ZZFTransition *)transitionAnimationWithType:(ZZFTransitionType)type{ ZZFTransition *transition = [[ZZFTransition alloc]init]; transition.type = type; return transition; } 複製程式碼
在.m檔案中實現transitionAnimationWithType類方法,初始化例項物件,設定動畫型別,返回物件。
2:實現UIViewControllerAnimatedTransitioning協議中的方法
-(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的動畫實現放到一個方法中去,這裡的程式碼更簡潔。
- (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動畫就完成了,下邊是使用的方法。
3:自定義動畫的使用
在需要執行自定義動畫的控制器中,遵守 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自定義動畫,同理。
4:注意點
執行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; } 複製程式碼