你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> 自定義presentViewController的轉場動畫(Swift)

自定義presentViewController的轉場動畫(Swift)

編輯:IOS開發綜合

前言:

iOS默認的presentViewController的切換動畫是從底部推入,消失是從頂部推出。但是,因為iOS系統默認的是適配所有轉場上下文的。而針對特定的轉場上下文,我們能做出更好的效果。

Tips:所謂的轉場上下文,就是轉場的開始View和結束View,以及對應的ViewController


目標效果

最終的效果


准備工作

首先寫出一個CollectionView,每個Cell是一個圖片,由於本文的核心是如何轉場,所以CollectionView的部分略過。寫完了之後,是這樣的效果

點擊某一個CollectionView Cell查看大圖,再點擊大圖圖片消失

 


如何實現自定義轉場動畫

iOS 8之後,我們可以通過設置ViewControllertransitioningDelegate來設置代理來處理轉場動畫。

通過文檔,可以看到transitioningDelegate是一個實現UIViewControllerTransitioningDelegate協議的對象,先看看這個協議,本文主要利用以下兩個方法

animationControllerForDismissedController animationControllerForPresentedController

著兩個方法的目的是,提供一個遵循UIViewControllerAnimatedTransitioning協議的對象,然後又這個對象來實際處理專場。通過名字就可以看出來,一個是處理present一個是處理dismiss。

本文的設計是讓ViewController來處理轉場,在didSelectItemAtIndexPath中,設置pvc的轉場代理

dvc.transitioningDelegate = self

然後,寫一個extension來實現協議

extension ViewController:UIViewControllerTransitioningDelegate{
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return nil
    }
    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return nil
    }
}

這時候,再運行項目,會發現沒有任何變化,還是默認的轉場方式。因為我們還沒有提供實際的動畫 。當上述兩個代理方法返回nil的時候,系統會使用默認的方式


實現UIViewControllerAnimatedTransitioning

新建一個文件,命名為Animator.swift,然後新建一個類,處理Present的轉場(Dismiss類似),實現UIViewControllerAnimatedTransitioning協議

class PresentAnimator: NSObject,UIViewControllerAnimatedTransitioning{
}

這時候,會報錯沒有實現協議,然後,我們添加協議方法,這時候的Animator.swift如下

import Foundation
import UIKit

class PresentAnimator: NSObject,UIViewControllerAnimatedTransitioning{
    let duration = 0.5 //動畫的時間
    var originFrame = CGRectZero //點擊Cell的frame
    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        return duration
    }
    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

    }
}

簡單介紹下這裡的協議方法

transitionDuration,返回轉場動畫的時間 animateTransition,進行實際的轉場動畫,通過參數transitionContext(轉場上下文)來獲取轉場的fromView,toView,fromViewController,toViewController。

轉場的原理

轉場開始的時候,自動把FromView添加到轉場ContainView 轉場結束的時候,自動把FromView移除ContainView

所以,開發者要做的就是

把toView添加到轉場ContainView中,並且定義好toView的初始位置和狀態 定義好FromView和ToView的轉場結束時候的狀態 創建動畫

實現實際的轉場動畫

基於上述的原理,我們修改實際的動畫

     func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        let containView = transitionContext.containerView()
        let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!

        let finalFrame = toView.frame

        let xScale = originFrame.size.width/toView.frame.size.width
        let yScale = originFrame.size.height/toView.frame.size.height
        toView.transform = CGAffineTransformMakeScale(xScale, yScale)
        toView.center = CGPointMake(CGRectGetMidX(originFrame), CGRectGetMidY(originFrame))

        containView?.addSubview(toView)
        UIView.animateWithDuration(duration, animations: { () -> Void in
            toView.center = CGPointMake(CGRectGetMidX(finalFrame), CGRectGetMidY(finalFrame))
            toView.transform = CGAffineTransformIdentity
            }) { (finished) -> Void in
                transitionContext.completeTransition(true)
        }
    }

然後,在ViewController.swfit中,添加一屬性

    let presentAnimator = PresentAnimator()

修改didSelectItemAtIndexPath

    override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        let dvc = DetailViewController()
        dvc.image = UIImage(named: "image.jpg")
        dvc.transitioningDelegate = self
        let cell =  collectionView.cellForItemAtIndexPath(indexPath) as! FullImageCell
        presentAnimator.originFrame = cell.convertRect(cell.imageview.frame, toView: nil)
        self.presentViewController(dvc, animated: true, completion: nil)
    }

修改代理方法

    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return presentAnimator
    }

這時候的動畫效果如Gif


同理,為dismiss添加轉場動畫

在Animator.swift中添加一個新的類

class DismisssAnimator:NSObject,UIViewControllerAnimatedTransitioning{
    let duration = 0.6
    var originFrame = CGRectZero
    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        return duration
    }
    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        let containView = transitionContext.containerView()
        let toView = transitionContext.viewForKey(UITransitionContextToViewKey)! //Collection View
        let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)! //全屏的imageview
        let xScale = originFrame.size.width/toView.frame.size.width
        let yScale = originFrame.size.height/toView.frame.size.height
        containView?.addSubview(toView)
        containView?.bringSubviewToFront(fromView)
        UIView.animateWithDuration(duration, animations: { () -> Void in
            fromView.center = CGPointMake(CGRectGetMidX(self.originFrame), CGRectGetMidY(self.originFrame))
            fromView.transform = CGAffineTransformMakeScale(xScale, yScale)
            }) { (finished) -> Void in
                transitionContext.completeTransition(true)
        }
    }
}

然後,在ViewController.swift中didSelectItemAtIndexPath設置presentAnimator.frame下一行添加

 dismissAnimator.originFrame = cell.convertRect(cell.imageview.frame, toView: nil)

其中,dismissAnimator是ViewController的一個屬性

    let dismissAnimator = DismisssAnimator()

然後,在代理方法中,返回

 func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return dismissAnimator;
    }

最終的效果

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved