UIView Animation 學習筆記 應用示例

目錄

示例一 視圖內動畫

1. 準備

  1. 使用Xcode建立一個"Single View Application"項目
  2. 從控件庫中選擇一個標籤(Label)以及一個按鈕(Button)放在默認的視圖上
  3. 設置標籤(水平居中、垂直居中)以及按鈕(寬度、距離屏幕下邊框的位置、水平居中)的約束
  4. 將標籤的兩個約束使用Ctrl拖拽到對應的ViewController當中,並分別命名爲centerXAligncenterYAlign
  5. 使用Ctrl拖動按鈕到代碼中,並命名其爲button
  6. 添加並重載方法viewWillAppearviewDidAppear

準備完成後,代碼部分以下所示:swift

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var centerXAlign: NSLayoutConstraint!
    @IBOutlet weak var centerYAlign: NSLayoutConstraint!
    
    @IBOutlet weak var button: UIButton!
    
    // ... 

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        
    }
    
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

    }
}

2. 添加水平移入動畫

根據以前的準備,咱們能夠開始進行動畫效果的編寫。爲了讓標籤實現水平移入的動畫效果,咱們須要改變標籤的初始位置到屏幕的外面。以下所示:app

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    
    centerXAlign.constant -= view.bounds.width
}

viewWillAppear方法用於執行在視圖尚未顯現,可是將要顯現時候,須要進行的操做。.constant爲約束的值。view.bounds表示當前視圖的邊界。ide

注意:上面代碼中centerXAlign.constant減去的內容並非其精確的須要減去的數值,只是出於方便的考慮才直接使用視圖的寬度進行設置。學習

在視圖將要載入時,將要顯示的內容移除屏幕後,咱們須要在視圖完成顯示時,再將屏幕外的標籤移動進來。因爲想要達到水平移動的效果,咱們只須要改變標籤水平約束的值就能夠了。以下所示:動畫

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    
    UIView.animateWithDuration(1.0, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
        self.centerXAlign.constant += self.view.bounds.width
        
        self.view.layoutIfNeeded()
    }, completion: nil)
}

咱們設置標籤移入動畫的持續時間爲1秒,延遲0秒執行,使用.CurveEaseOut效果執行動畫。動畫的內容爲對標籤的約束執行「加」操做,並調用self.view.layoutIfNeeded()方法,使動畫效果生效。.net

此時,咱們執行程序將會發現,標籤從屏幕的右方水平移入。設計

注意:全部的動畫效果,都是經過改變UIView實例的以下屬性來進行的。code

  • center —— 中心
  • alpha —— 透明度
  • frame —— 邊框
  • bounds —— 約束
  • transform —— 切換
  • backgroundColor —— 背景色
  • contentStretch —— 內容縮放

3. 添加彈性動畫

以前咱們已經完成對標籤水平移入的操做,這裏咱們爲以前添加的按鈕添加彈性動畫的效果。按鈕將在標籤水平移入後,執行彈性動畫。具體實現以下所示:orm

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    
    // ...
    
    let bounds = self.button.bounds
    UIView.animateWithDuration(2.0, delay: 1.2, usingSpringWithDamping: 0.1, initialSpringVelocity: 100.0, options: nil, animations: {

        self.button.bounds = CGRect(x: bounds.origin.x - 80, y: bounds.origin.y, width: bounds.size.width + 160, height: bounds.height)

        }, completion: nil)
}

在上面的代碼中,咱們經過使用一個新的矩形描述改變按鈕的邊界值,從而實現對按鈕大小改變的彈性動畫。blog

示例二 視圖間切換

1. 準備

  1. 新建一個Xcode iOS項目,類型選擇「Single View Application」
  2. 打開StoryBoard,拖入一個View Controller
  3. 向項目添加文件,分別爲「ActionViewController.swift」、「CustomPresentAnimationController.swift」、「CustomDismissAnimationController.swift」、「CustomNavigationAnimationController.swift」。其中「ActionViewController.swift」爲UIViewController的子類,「CustomPresentAnimationController.swift」、「CustomDismissAnimationController.swift」「CustomNavigationAnimationController.swift」、「CustomNavigationAnimationController.swift」爲NSObject的子類。
  4. 設置新拖入的View Controller的類爲ActionViewController
  5. 設置Action View Controller的背景色,並拖入一個按鈕,修改按鈕標題爲「Dismiss」
  6. 爲主視圖添加一個導航條按鈕,並添加到Action View Controller的Segue,設置Segue的類型爲Present Modal,用於彈出Action View Controller
  7. 爲主視圖添加一個按鈕,並修改文字爲「Toggle Navigation Transition」
  8. 拖拽一個ViewController到畫板,而後關聯「Toggle Navigation Transition」按鈕到新添加的ViewController

注意:

  • 在向項目添加文件的時候,要注意不要選擇了OSX應用類型。

2. 視圖出現切換效果

向CustomPresentAnimationController.swift文件添加以下代碼。

import UIKit

class CustomPresentAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
        return 5.0
    }

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        
        let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
        let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
        let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
        let containerView = transitionContext.containerView()
        
        let bounds = UIScreen.mainScreen().bounds
        toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.size.height)
        containerView.addSubview(toViewController.view)
        
        UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .CurveLinear, animations: {
            fromViewController.view.alpha = 0.5
            toViewController.view.frame = finalFrameForVC
            }, completion: {
                finished in
                transitionContext.completeTransition(true)
                fromViewController.view.alpha = 1.0
        })
    }
}

向ViewController.swift文件添加以下代碼。

import UIKit

class ViewController: UIViewController, UIViewControllerTransitioningDelegate {

    // ...
    
    let customPresentAnimationController = CustomPresentAnimationController()
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        
        if segue.identifier == "showAction" {
            let toViewController = segue.destinationViewController as! UIViewController
            toViewController.transitioningDelegate = self
        }
    }
    
    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return customPresentAnimationController
    }    
}

輸入圖片說明

3. 視圖消失切換效果

向CustomDismissAnimationController.swift添加以下代碼。

import UIKit

class CustomDismissAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
        return 1.0
    }
    
    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        
        let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
        let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
        let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
        let containerView = transitionContext.containerView()
        
        toViewController.view.frame = finalFrameForVC
        toViewController.view.alpha = 0.5
        containerView.addSubview(toViewController.view)
        containerView.sendSubviewToBack(toViewController.view)
        
        UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
            fromViewController.view.frame = CGRectInset(fromViewController.view.frame, fromViewController.view.frame.size.width / 2, fromViewController.view.frame.size.height / 2)
            toViewController.view.alpha = 1.0
            }, completion: {
                finished in
                transitionContext.completeTransition(true)
        })
    }
}

向ViewController.swift添加以下代碼。

import UIKit

class ViewController: UIViewController, UIViewControllerTransitioningDelegate {

    // ..

    // MARK: - for Segue's present modally action
    
    // ...

    let customDismissAnimationController = CustomDismissAnimationController()
    
    @IBAction func dimssViewController(segue: UIStoryboardSegue) {
        
    }
    
    // MARK: - UIViewControllerTransitioningDelegate's method
    
    // ...
    
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return customDismissAnimationController
    }
}

輸入圖片說明

4. 視圖導航切換效果

向CustomNavigationAnimationController.swift添加以下代碼。(其實是使用第三步的切換效果)

import UIKit

class CustomNavigationAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
    
    func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
        return 2.0
    }
    
    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
        let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
        let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
        let containerView = transitionContext.containerView()
        
        toViewController.view.frame = finalFrameForVC
        toViewController.view.alpha = 0.5
        containerView.addSubview(toViewController.view)
        containerView.sendSubviewToBack(toViewController.view)
        
        UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
            fromViewController.view.frame = CGRectInset(fromViewController.view.frame, fromViewController.view.frame.size.width / 2, fromViewController.view.frame.size.height / 2)
            toViewController.view.alpha = 1.0
            }, completion: {
                finished in
                transitionContext.completeTransition(true)
        })
    }
}

向ViewController.swift添加以下代碼。

import UIKit

class ViewController: UIViewController, UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {

    // ...

    // MARK: - for Segue's present modally action
    
    // ...

    let customNavigationAnimationController = CustomNavigationAnimationController()
    
    // MARK: - UIViewControllerTransitioningDelegate's method
    
    // ...
    
    // MARK: - UINavigationControllerDelegate's method
    
    func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return customNavigationAnimationController
    }
}

輸入圖片說明

添加交互

注:此效果是後來添加的,因爲在設計Demo的時候沒有考慮到,因此就在Demo項目中就沒有實現。代碼來自參考的文章。

新建一個「CustomInteractionController」類。並編輯這個類文件爲以下所示。

import UIKit

class CustomInteractionController: UIPercentDrivenInteractiveTransition {
    
    var navigationController: UINavigationController!
    var shouldCompleteTransition = false
    var transitionInProgress = false
    
    var completionSeed: CGFloat {
        return 1 - percentComplete
    }
    
    func attachToViewController(viewController: UIViewController) {
        navigationController = viewController.navigationController
        setupGestureRecognizer(viewController.view)
    }
    
    private func setupGestureRecognizer(view: UIView) {
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "handlePanGesture:"))
    }
    
    func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) {
        let viewTranslation = gestureRecognizer.translationInView(gestureRecognizer.view!.superview!)
        switch gestureRecognizer.state {
        case .Began:
            transitionInProgress = true
            navigationController.popViewControllerAnimated(true)
        case .Changed:
            var const = CGFloat(fminf(fmaxf(Float(viewTranslation.x / 200.0), 0.0), 1.0))
            shouldCompleteTransition = const > 0.5
            updateInteractiveTransition(const)
        case .Cancelled, .Ended:
            transitionInProgress = false
            if !shouldCompleteTransition || gestureRecognizer.state == .Cancelled {
                cancelInteractiveTransition()
            } else {
                finishInteractiveTransition()
            }
        default:
            println("Swift switch must be exhaustive, thus the default")
        }
    }
}

向ViewController.swift文件添加以下代碼。

//
//  ViewController.swift
//  ViewTransition
//
//  Created by CongJunfeng on 15/8/2.
//  Copyright (c) 2015年 46day. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {

    // ...

    // MARK: - for Segue's present modally action
    
    // ...
    
    let customInteractionController = CustomInteractionController() // for Interaction
    
    // MARK: - UIViewControllerTransitioningDelegate's method
    
    // ...
    
    // MARK: - UINavigationControllerDelegate's method
    
    func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        
        /**
        *  for Interaction
        */
        if operation == .Push {
            customInteractionController.attachToViewController(toVC)
        }
        
        return customNavigationAnimationController
    }
    
    // for Interaction
    func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        return customInteractionController.transitionInProgress ? customInteractionController : nil
    }
}

參考

相關文章
相關標籤/搜索