• <menu id="w2i4a"></menu>
  • logo 移動開發(fā)學習指南
    文檔首頁>>移動開發(fā)學習指南>>iOS開發(fā)文集iOS 10 Day By Day:UIViewPropertyAnimator屬性

    iOS開發(fā)文集iOS 10 Day By Day:UIViewPropertyAnimator屬性


    基于UIView的動畫block在動畫屬性(框架、變換,等等)之間添加過渡,輕松建立。他們創(chuàng)建起來是難以置信的容易,只需要幾行代碼:

    view.alpha = 1
    UIView.animate(withDuration: 2) {
        containerView.alpha = 0
    }

    你還可以添加completion blocks,當動畫完成時它們將被執(zhí)行,如果默認的線性運動不能運行則調(diào)整動畫曲線。

    然而,如果你需要創(chuàng)建你自己的自定義動畫曲線,就需要被動畫迅速啟動的屬性,然后迅速減速,這時會發(fā)生什么呢?另一個稍微棘手的問題是你需要取消一個運行中的動畫。當然這些可以通過使用第三方庫或創(chuàng)建一個新的動畫更換目前正在進行的動畫來解決,蘋果增加了一個新的組件到UIKit框架,使得這個問題解決起來變得容易許多:進入UIViewPropertyAnimator。

    一個新的動畫時代

    UIViewPropertyAnimator是寫得很好的且高度可擴展的API。它涵蓋了許多與“舊式”UIView動畫相同的功能,但能給你動畫的精確編程控制。這意味著你可以暫停一個進度,在稍后的某個日期如果你愿意的話再啟動它,甚至可以動態(tài)修改動畫屬性(比如將以前左下角的動畫結束點位置改變到屏幕的右上方)。

    為了探索這個新的類,我們將看幾個我們在屏幕上制作的圖像動畫的例子。像所有的Day by Day博客一樣,代碼放在GitHub上(為了方便各位讀者,小編已經(jīng)為大家整理了,請點擊這里下載)。這一次,我們要使用一個Playground。

    Playground演練

    我們所有的Playground頁面都有一個忍者在屏幕上移動。為了使頁面盡可能的貼切,我們將我們共同的代碼隱藏在Sources文件夾里。這不僅是幫助你簡化你的頁面的代碼,也使他們的運行速度同源被編譯了一樣快。

    源包含一個簡單的UIView子類,叫做NinjaContainerView。這個通過用顯示我們的忍者的UIImageView子視圖簡單設置了視圖。我已將圖像添加到Playground的Resources組里。

    import UIKit
    public class NinjaContainerView: UIView {
        public let ninja: UIImageView = {
            let image = UIImage(named: "ninja")
            let view = UIImageView(image: image)
            view.frame = CGRect(x: 0, y: 0, width: 45, height: 39)
            return view
        }()
        public override init(frame: CGRect) {
            // Animating view
            super.init(frame: frame)
            // Position ninja in the bottom left of the view
            ninja.center = {
                let x = (frame.minX + ninja.frame.width / 2)
                let y = (frame.maxY - ninja.frame.height / 2)
                return CGPoint(x: x, y: y)
            }()
            // Add image to the container
            addSubview(ninja)
            backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
        }
        required public init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        /// Moves the ninja view to the bottom right of its container, positioned just inside.
        public func moveNinjaToBottomRight() {
            ninja.center = {
                let x = (frame.maxX - ninja.frame.width / 2)
                let y = (frame.maxY - ninja.frame.height / 2)
                return CGPoint(x: x, y: y)
            }()
        }
    }

    現(xiàn)在,在每個Playground頁面,我們可以復制和粘貼以下代碼:

    import UIKit
    import PlaygroundSupport
    // Container for our animating view
    let containerView = NinjaContainerView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
    let ninja = containerView.ninja
    // Show the container view in the Assistant Editor
    PlaygroundPage.current.liveView = containerView

    這將使用Playground有用的“Live View”功能,無需啟動模擬器就可以給我們一個我們的動畫的可視化演示。他們?nèi)匀挥凶约旱姆绞?,但Playgrounds是嘗試新東西的明智之舉。

    要顯示Live View窗格,導航到View > Assistant Editor > Show Assistant Editor,或者,選擇在工具欄中右上方看起來像兩個相交圓的圖標。如果你在Assistant Editor中沒有看到Live View,要確保已選擇了Timeline,而不是Manual,比起我認識到這一點,我已經(jīng)失去了更多的時間!

    從簡單的開始

    我們可以用同舊式的基于block的API完全相同的方式使用UIViewPropertyAnimator :

    UIViewPropertyAnimator(duration: 1, curve: .easeInOut) {
        containerView.moveNinjaToBottomRight()
    }.startAnimation()

    這將啟動一個持續(xù)1秒的動畫,有一個簡化后的時間曲線。執(zhí)行的動畫在關閉中。

    iOS開發(fā)文集iOS 10 Day By Day:UIViewPropertyAnimator屬性

    請注意,我們必須通過調(diào)用startAnimation()明確啟動動畫。另一種方法來創(chuàng)建無需自身啟動的動畫是使用runningPropertyAnimator(withDuration:delay:options:animations:completion:)——一個公平的mouthful,所以你可能更喜歡使用手動啟動版。

    在動畫已經(jīng)創(chuàng)建之后,添加額外的動畫是很容易的。

    // Now we've set up our view, let's animate it with a simple animation
    let animator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut)
    // Add our first animation block
    animator.addAnimations {
        containerView.moveNinjaToBottomRight()
    }
    // Now here goes our second
    animator.addAnimations {
        ninja.alpha = 0
    }

    這些動畫blocks會跑在一起。

    iOS開發(fā)文集iOS 10 Day By Day:UIViewPropertyAnimator屬性

    Completion blocks可以以類似的方式添加:

    animator.addCompletion {
        _ in
        print("Animation completed")
    }
    animator.addCompletion {
        position in
        switch position {
        case .end: print("Completion handler called at end of animation")
        case .current: print("Completion handler called mid-way through animation")
        case .start: print("Completion handler called  at start of animation")
        }
    }

    在動畫被允許運行它的整個持續(xù)時間的情況下,我們將看到以下版塊:

    Animation completed
    Completion handler called at end of animation

    滑動和反向

    我們可以使用animator來滑動我們的動畫:

    let animator = UIViewPropertyAnimator(duration: 5, curve: .easeIn)
    // Add our first animation block
    animator.addAnimations {
        containerView.moveNinjaToBottomRight()
    }
    let scrubber = UISlider(frame: CGRect(x: 0, y: 0, width: containerView.frame.width, height: 50))
    containerView.addSubview(scrubber)
    let eventListener = EventListener()
    eventListener.eventFired = {
        animator.fractionComplete = CGFloat(scrubber.value)
    }
    scrubber.addTarget(eventListener, action: #selector(EventListener.handleEvent), for: .valueChanged)
    iOS開發(fā)文集iOS 10 Day By Day:UIViewPropertyAnimator屬性

    Playground是很棒的,你甚至可以添加交互式UI元素到Live View中。不幸的是,接收事件是痛苦的,因為我們需要一個符合NSObject可以監(jiān)聽事件的類,像是.valueChanged。為此,當handleEvent方法被調(diào)用時,我們用一個簡單的對象EventHandler調(diào)用我們的eventFired關閉。


    分數(shù)與時間無關,所以我們看不到我們的忍者在一個像我們定義的優(yōu)雅的easeIn曲線上移動。

    屬性動畫的真正力量來自于能夠中斷正在進行的動畫的能力。我們可以通過簡單的切換isReversed屬性來反向移動動畫。

    為了說明這一點,我們使用關鍵幀動畫,這樣我們就可以定義一個多級動畫:

    animator.addAnimations {
        UIView.animateKeyframes(withDuration: animationDuration, delay: 0, options: [.calculationModeCubic], animations: {
            UIView.addKeyframe(withRelativeStartTime: 0,  relativeDuration: 0.5) {
                ninja.center = containerView.center
            }
            UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
                containerView.moveNinjaToBottomRight()
            }
        })
    }
    let button = UIButton(frame: CGRect(origin: .zero, size: CGSize(width: 100, height: 30)))
    button.setTitle("Reverse", for: .normal)
    button.setTitleColor(.black(), for: .normal)
    button.setTitleColor(.gray(), for: .highlighted)
    let listener = EventListener()
    listener.eventFired = {
        animator.isReversed = true
    }
    button.addTarget(listener, action: #selector(EventListener.handleEvent), for: .touchUpInside)
    containerView.addSubview(button)
    animator.startAnimation()

    當按下按鈕,屬性動畫將反轉(zhuǎn)動畫,如果其狀態(tài)是激活的(即動畫目前在運行中,忍者尚未到達其最終目的地)。

    iOS開發(fā)文集iOS 10 Day By Day:UIViewPropertyAnimator屬性

    添加你自己的時間曲線

    屬性動畫是很簡單的,其余是漂亮的擴展。如果你需要另一種蘋果所提供的動畫曲線,你可以通過你自己符合UITimingCurveProvider協(xié)議的情況。在大多數(shù)情況下,你可能會使用UICubicTimingParameters或UISpringTimingParameters。

    我們說我們的忍者加速真的很快,然后在屏幕上他們的旅途中出現(xiàn)一個漸進的停止。我們將使用Bezier曲線,如下圖(使用這個方便的在線工具繪制)。

    iOS開發(fā)文集iOS 10 Day By Day:UIViewPropertyAnimator屬性
    let bezierParams = UICubicTimingParameters(controlPoint1: CGPoint(x: 0.05, y: 0.95),
                                                       controlPoint2: CGPoint(x: 0.15, y: 0.95))
    let animator = UIViewPropertyAnimator(duration: 4, timingParameters:bezierParams)
    animator.addAnimations {
        containerView.moveNinjaToBottomRight()
    }
    animator.startAnimation()
    iOS開發(fā)文集iOS 10 Day By Day:UIViewPropertyAnimator屬性

    進一步的閱讀

    新的屬性動畫通過帶來在一致的API下的現(xiàn)有能力,看起來會讓動畫項目比以往任何時候都容易,增加了中斷動畫和你自己的自定義時序曲線的能力。

    蘋果提供了一些優(yōu)秀的UIViewPropertyAnimator文件?;蛘?,你可以觀看WWDC演講,將在新的API進行深入研究和探討可以用來如何創(chuàng)建UIViewControllers之間的自定義轉(zhuǎn)換。其他有趣的演示也包括了簡單的游戲。

    本文翻譯自:iOS 10 Day By Day: UIViewPropertyAnimator

     

    PS: 關于移動開發(fā),這些產(chǎn)品你可以關注>>
    關于移動開發(fā)的最新資訊和產(chǎn)品推薦,請<咨詢在線客服>!
    掃碼咨詢


    添加微信 立即咨詢

    電話咨詢

    客服熱線
    023-68661681

    TOP
    三级成人熟女影院,欧美午夜成人精品视频,亚洲国产成人乱色在线观看,色中色成人论坛 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();