
通過- (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];
項目源碼
下載地址