通過- (void)presentViewController:animated:completion:
方法跳轉到另一個頁面時,可以自定義modal動畫。
從代碼的角度看,啟用動畫的入口是這樣的:
vc.transitioningDelegate = self; [self presentViewController:vc animated:YES completion:nil];
給vc的transitioningDelegate屬性賦值,為即將跳轉的vc指定轉場動畫代理。簡單起見,在這裡,當前controller自己充當了代理。而作為代理需要實現
協議。
@interface ViewController ()
協議中有兩個基礎方法,分別要求代理返回present時的動畫以及dismiss時的動畫。
- (nullable id )animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source; - (nullable id )animationControllerForDismissedController:(UIViewController *)dismissed;
剩下的事情,就需要代理去考慮怎麼搞出兩個實現了
協議的動畫對象來。
我們可以寫一個類專門來實現
動畫協議,作為動畫的實現類。然後代理就可以輕松搞出兩個動畫對象,實現
轉場代理協議。
@interface PictureBroswerTransitionAnimator : NSObject
在
動畫協議中,有兩個必須實現的方法:
/// 返回動畫持續時間- (NSTimeInterval)transitionDuration:(nullable id )transitionContext;/// 動畫實現過程- (void)animateTransition:(id )transitionContext;
可以看到,其中的關鍵方法就是-(void)animateTransition:
,系統會向此方法傳入一個參數transitionContext
,它代表了整個轉場環境,包含了轉場過程中的關鍵信息,比如從哪裡轉到哪裡。
實現動畫的關鍵方法
- (void)animateTransition:(id
)transitionContext
獲取轉場過程的三個視圖:containerView、fromView、toView。
containerView是動畫過程中提供的暫時容器。
fromView是轉場開始頁的視圖。
toView是轉場結束頁的視圖。
UIView *fromView;UIView *toView;if ([transitionContext respondsToSelector:@selector(viewForKey:)]) { // iOS8以上用此方法准確獲取 fromView = [transitionContext viewForKey:UITransitionContextFromViewKey]; toView = [transitionContext viewForKey:UITransitionContextToViewKey]; }else { fromView = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view; toView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view; }UIView *container = [transitionContext containerView];
轉場的過程,大多數情況下我們都是對toView作各種變換操作,例如改變toView的alpha,size,旋轉等等。 在對它進行操作前,需要先把它放到container上才能顯示出來。[container addSubview:toView];
最後需要我們自己弄出個動畫來~囧
pictureView.transform = startTransform; pictureView.center = startCenter; [UIView animateWithDuration:self.duration animations:^{ pictureView.transform = endTransform; pictureView.center = endCenter; } completion:^(BOOL finished) { BOOL wasCancelled = [transitionContext transitionWasCancelled]; [transitionContext completeTransition:!wasCancelled]; }];
這裡注意一下,在我們自己寫的動畫完結時,一定要告訴所在的轉場環境對象transitionContext
,我們的動畫完成了,它才會進行動畫結束後的收尾工作:
[transitionContext completeTransition:YES];
在轉場的過程中,動畫有可能被各種原因打斷,通過transitionWasCancelled
方法可以知道是否被打斷:
BOOL wasCancelled = [transitionContext transitionWasCancelled]; [transitionContext completeTransition:!wasCancelled];
項目源碼
下載地址