轉場須要提供轉場代理,不使用默認的代理則須要本身實現代理方式,有UINavigationController、UITabBarController、UIViewController三種代理,實現如下三種協議
<UINavigationControllerDelegate> //push和pop切換 <UITabBarControllerDelegate> //tab切換
<UIViewControllerTransitioningDelegate> //UICollectionViewController 與 UINavigationController 結合的轉場方式
轉場觸發時,須要UIKit 將要求轉場代理將提供轉場動畫的核心構件:動畫控制器和交互控制器
動畫控制器(Animation Controller):
最重要的部分,負責添加視圖以及執行動畫;遵照<UIViewControllerAnimatedTransitioning>
協議;由咱們實現。html
交互控制器ios
經過交互手段,一般是手勢來驅動動畫控制器實現的動畫,使得用戶可以控制整個過程;遵照<UIViewControllerInteractiveTransitioning>
協議;系統已經打包好現成的類供咱們使用app
轉場環境(Transition Context):dom
提供轉場中須要的數據;遵照<UIViewControllerContextTransitioning>
協議;由 UIKit 在轉場開始前生成並提供給咱們提交的動畫控制 器和交互控制器使用。ide
轉場協調器(Transition Coordinator):動畫
可在轉場動畫發生的同時並行執行其餘的動畫,其做用與其說協調不如說輔助,主要在 Modal 轉場和交互轉場取消時使用,其餘時候不多用到;遵照<UIViewControllerTransitionCoordinator>
協議;由 UIKit 在轉場時生成,UIViewController 在 iOS 7 中新增了方法transitionCoordinator()
返回一個遵照該協議的對象,且該方法只在該控制器處於轉場過程當中才返回一個此類對象,不參與轉場時返回 nilui
動畫控制器協議實現:
//返回動畫時間this
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {spa
return self.duration;3d
}
//執行動畫
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
//返回容器視圖,轉場發生的地方
//獲取參與轉場的視圖控制器,有 UITransitionContextFromViewControllerKey 和 UITransitionContextToViewControllerKey 兩個 Key。
//經過viewForKey:獲取的視圖是viewControllerForKey:返回的控制器的根視圖,或者 nil。viewForKey:方法返回 nil 只有一種狀況: UIModalPresentationCustom 模式下的 Modal 轉場 ,經過此方法獲取 presentingView 時獲得的將是 nil,在後面的 Modal 轉場裏會詳細解釋。
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *toView = toVC.view;
UIView *fromView = fromVC.view;
[self animateTransition:transitionContext fromVC:fromVC toVC:toVC fromView:fromView toView:toView];
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext fromVC:(UIViewController *)fromVC toVC:(UIViewController *)toVC fromView:(UIView *)fromView toView:(UIView *)toView {
// Add the toView to the container
UIView* containerView = [transitionContext containerView];
[containerView addSubview:toView];
[containerView sendSubviewToBack:toView];
CGSize size = toView.frame.size;
NSMutableArray *snapshots = [NSMutableArray new];
CGFloat xFactor = 10.0f;
CGFloat yFactor = xFactor * size.height / size.width;
// snapshot the from view, this makes subsequent snaphots more performant
UIView *fromViewSnapshot = [fromView snapshotViewAfterScreenUpdates:NO];
// create a snapshot for each of the exploding pieces
for (CGFloat x=0; x < size.width; x+= size.width / xFactor) {
for (CGFloat y=0; y < size.height; y+= size.height / yFactor) {
CGRect snapshotRegion = CGRectMake(x, y, size.width / xFactor, size.height / yFactor);
UIView *snapshot = [fromViewSnapshot resizableSnapshotViewFromRect:snapshotRegion afterScreenUpdates:NO withCapInsets:UIEdgeInsetsZero];
snapshot.frame = snapshotRegion;
[containerView addSubview:snapshot];
[snapshots addObject:snapshot];
}
}
[containerView sendSubviewToBack:fromView];
// animate
NSTimeInterval duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:duration animations:^{
for (UIView *view in snapshots) {
CGFloat xOffset = [self randomFloatBetween:-100.0 and:100.0];
CGFloat yOffset = [self randomFloatBetween:-100.0 and:100.0];
view.frame = CGRectOffset(view.frame, xOffset, yOffset);
view.alpha = 0.0;
view.transform = CGAffineTransformScale(CGAffineTransformMakeRotation([self randomFloatBetween:-10.0 and:10.0]), 0.01, 0.01);
}
} completion:^(BOOL finished) {
for (UIView *view in snapshots) {
[view removeFromSuperview];
}
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
- (float)randomFloatBetween:(float)smallNumber and:(float)bigNumber {
float diff = bigNumber - smallNumber;
return (((float) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * diff) + smallNumber;
}
參考連接:http://blog.devtang.com/2016/03/13/iOS-transition-guide/