自定義present和dismiss的轉場動畫

Eric君發表於2018-01-03

趁週末閒暇之餘,重新寫一下present和push的自定義動畫。 本來之前有寫過一個,因為沒有及時整理,到導致一時凌亂,找不到具體在哪了,提醒各位,平時要注意程式碼的整理和歸檔,不然到時候重複的程式碼寫了又寫,那就得不償失了。廢話不過說,先看下下面的效果:

效果圖展示

原生的present是從底部向上彈出相應的檢視控制器,而push動畫,則是將檢視從右邊推出來進行展示,為了檢視展示的統一性,需要自定義轉場動畫,將present改成從右往左推出來展示,在dismiss的VC中需要增加一個左邊的手勢,以滿足側滑返回的效果。

首先需要主頁VC實現UIViewControllerTransitioningDelegate這個代理中的2個方法

#pragma mark - UIViewControllerTransitioningDelegate
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
    return [[YQPresentTransitionAnimated alloc] init];
}

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    return [[YQDismissTransitionAnimated alloc] init];
}
複製程式碼

將它的present動畫和dismiss動畫交給我們自定義的動畫來管理。

####present動畫的自定義#### 1.建立一個類,繼承至NSObject,並實現UIViewControllerAnimatedTransitioning的代理;

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface YQPresentTransitionAnimated : NSObject<UIViewControllerAnimatedTransitioning>

@end
複製程式碼

2.實現代理的2個方法

//1.定義轉場動畫的時間
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 0.4;
}

//2.實現轉場動畫的動畫效果
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];   //主頁VC
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];     //present的VC
    
    UIView *containerView = transitionContext.containerView;  //轉場的容器檢視,動畫完成後,會消失
    UIView *fromView;
    UIView *toView;

    if ([transitionContext respondsToSelector:@selector(viewForKey:)]) {
        fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
        toView = [transitionContext viewForKey:UITransitionContextToViewKey];
    } else {
        fromView = fromViewController.view;
        toView = toViewController.view;
    }
    
    //注意這個對應關係
    BOOL isPresenting = (toViewController.presentingViewController == fromViewController);
    
    CGRect fromFrame = [transitionContext initialFrameForViewController:fromViewController];
    CGRect toFrame = [transitionContext finalFrameForViewController:toViewController];
    
    if (isPresenting) {
        fromView.frame = fromFrame;
        toView.frame = CGRectOffset(toFrame, toFrame.size.width, 0);
    }
    
    if (isPresenting)
        [containerView addSubview:toView];
    
    NSTimeInterval transitionDuration = [self transitionDuration:transitionContext];
    
    [UIView animateWithDuration:transitionDuration animations:^{
        if (isPresenting) {
            toView.frame = toFrame;
            fromView.frame = CGRectOffset(fromFrame, fromFrame.size.width * 0.3 * -1, 0);
        }
    } completion:^(BOOL finished) {
        //固定寫法
        BOOL wasCancelled = [transitionContext transitionWasCancelled];
        
        if (wasCancelled)
            [toView removeFromSuperview];
        
        [transitionContext completeTransition:!wasCancelled];
    }];
}
複製程式碼

3.將主頁VC的transitioningDelegate設為自己,**【千萬注意】:**還需要將present的頁面的transitioningDelegate設為自己(主頁VC)

####dismiss動畫的自定義#### 跟上面的present步驟一樣,只需將動畫效果換成相反的即可。

附上原始碼: github.com/GitterYang/…

相關文章