iOS自定義轉(zhuǎn)場動(dòng)畫(push)

push.gif

iOS7 開始蘋果推出了自定義轉(zhuǎn)場的 API 。從此,任何可以用 CoreAnimation 實(shí)現(xiàn)的動(dòng)畫,都可以出現(xiàn)在兩個(gè) ViewController 的切換之間。并且實(shí)現(xiàn)方式高度解耦,這也意味著在保證代碼干凈的同時(shí)想要替換其他動(dòng)畫方案時(shí)只需簡單改一個(gè)類名就可以了。

自定義轉(zhuǎn)場動(dòng)畫Push

想在Push的時(shí)候?qū)崿F(xiàn)自定義轉(zhuǎn)場動(dòng)畫首先要遵守一個(gè)協(xié)議UINavigationControllerDelegate

蘋果在 UINavigationControllerDelegate 中給出了幾個(gè)協(xié)議方法,通過返回類型就可以很清楚地知道各自的具體作用。

//用來自定義轉(zhuǎn)場動(dòng)畫
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                   animationControllerForOperation:(UINavigationControllerOperation)operation
                                                fromViewController:(UIViewController *)fromVC
                                                  toViewController:(UIViewController *)toVC  NS_AVAILABLE_IOS(7_0);
//為這個(gè)動(dòng)畫添加用戶交互

- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                          interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);

在第一個(gè)方法里只要返回一個(gè)遵守UIViewControllerInteractiveTransitioning協(xié)議的對(duì)象,并在里面實(shí)現(xiàn)動(dòng)畫即可

創(chuàng)建繼承自 NSObject 并且聲明 UIViewControllerAnimatedTransitioning 的的動(dòng)畫類。

重載 UIViewControllerAnimatedTransitioning 中的協(xié)議方法。

//返回動(dòng)畫時(shí)間
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;

//將動(dòng)畫的代碼寫到里面即可
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;

首先自定義一個(gè)名為CustomAnimateTransitionPush的類繼承于NSObject準(zhǔn)守了UIViewControllerAnimatedTransitioning協(xié)議

self.transitionContext=transitionContext;

    // 獲取動(dòng)畫的源控制器和目標(biāo)控制器
    ViewController * fromVC = (ViewController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    PushViewController *toVC = (PushViewController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *contView = [transitionContext containerView];

    UIButton *button = fromVC.button;

    UIBezierPath *maskStartBP =  [UIBezierPath bezierPathWithOvalInRect:button.frame];
    // 都添加到container中。注意順序
    [contView addSubview:fromVC.view];
    [contView addSubview:toVC.view];


    //創(chuàng)建兩個(gè)圓形的 UIBezierPath 實(shí)例;一個(gè)是 button 的 size ,另外一個(gè)則擁有足夠覆蓋屏幕的半徑。最終的動(dòng)畫則是在這兩個(gè)貝塞爾路徑之間進(jìn)行的
    CGPoint finalPoint;
    //判斷觸發(fā)點(diǎn)在那個(gè)象限
    if(button.frame.origin.x > (toVC.view.bounds.size.width / 2)){
        if (button.frame.origin.y < (toVC.view.bounds.size.height / 2)) {
            //第一象限
            finalPoint = CGPointMake(button.center.x - 0, button.center.y - CGRectGetMaxY(toVC.view.bounds)+30);
        }else{
            //第四象限
            finalPoint = CGPointMake(button.center.x - 0, button.center.y - 0);
        }
    }else{
        if (button.frame.origin.y < (toVC.view.bounds.size.height / 2)) {
            //第二象限
            finalPoint = CGPointMake(button.center.x - CGRectGetMaxX(toVC.view.bounds), button.center.y - CGRectGetMaxY(toVC.view.bounds)+30);
        }else{
            //第三象限
            finalPoint = CGPointMake(button.center.x - CGRectGetMaxX(toVC.view.bounds), button.center.y - 0);
        }
    }


    CGFloat radius = sqrt((finalPoint.x * finalPoint.x) + (finalPoint.y * finalPoint.y));
    UIBezierPath *maskFinalBP = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(button.frame, -radius, -radius)];

    //創(chuàng)建一個(gè) CAShapeLayer 來負(fù)責(zé)展示圓形遮蓋

    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.path = maskFinalBP.CGPath; //將它的 path 指定為最終的 path 來避免在動(dòng)畫完成后會(huì)回彈
    toVC.view.layer.mask = maskLayer;

    CABasicAnimation *maskLayerAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
    maskLayerAnimation.fromValue = (__bridge id)(maskStartBP.CGPath);
    maskLayerAnimation.toValue = (__bridge id)((maskFinalBP.CGPath));
    maskLayerAnimation.duration = [self transitionDuration:transitionContext];
    maskLayerAnimation.timingFunction = [CAMediaTimingFunction  functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    maskLayerAnimation.delegate = self;

    [maskLayer addAnimation:maskLayerAnimation forKey:@"path"];

在控制器里面用來自定義轉(zhuǎn)場動(dòng)畫的方法里返回剛才自定義的動(dòng)畫類

-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{

    if(operation==UINavigationControllerOperationPush)
    {
        //自定義的動(dòng)畫類
        CustomAnimateTransitionPush *animateTransitionPush=[CustomAnimateTransitionPush new];
        return animateTransitionPush;
    }
    else
    {
        return nil;
    }

}

到此為止自定義轉(zhuǎn)場動(dòng)畫就完成了
pop的動(dòng)畫只是把push動(dòng)畫反過來做一遍。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容