WWDC2017-advanced_animations_with_uikit

最后修改时间: 2017-12-1

官方视频链接

这个Session主要讲一下的几个内容:

  • Basic(基础的): 动画工作原理 以及 动画如何计时
  • Interactive and Interruptible Animations: 可交互与可中断的动画
  • New Property Animator Behaviors: UIPropertyAnimator新的属性
  • Coordinating Animations: 协同动画
  • Tips And Tricks: 提示和技巧

一、 Basic(基础的)

  1. 传统的动画是线性的。

    UIView.animate(withDuration: 0.5) {
            circle.frame = circle.frame.offsetBy(dx: 100, dy: 0)
    }
    
    

image_1bqdda4oaksrr2f10av1t8b1dlu9.png-522kB

  1. UIViewPropertyAnimator 可以更好控制动画。包括: 可自定义time function更好交互(interactive)可中断(interruptible) 以及 更好响应Responsive

  2. 时间曲线(time curves): 本质就是一个函数,将时间转换为进度或者将动画所用的时间映射到动画的进度上。

  • 线性曲线(Liner Curves): 时间的进度比(%Progress) = 动画进度比(%time)。

动画是按照一定的曲线的来完成的。 该曲线在时间与动画进度上有一定的关系。
例如: 线性动画10s,动画完成50% 所化时间 10 * 50% =

    ![Snip20170920_27.png-219.4kB][2]
  • 非线性曲线也是按照时间进度函数来设置的。例如: easyOut
    Snip20170920_1.png-242kB

二、 Interactive and Interruptible Animations: 可交互与可中断的动画

2.1 Interactive(可交互动画)

```swift
    // 1. 实例化一个 animator
    var animator : UIViewPropertyAnimator!
    @objc func handlePan(recognizer: UIPanGestureRecognizer) {
        
        switch recognizer.state {
        case .began:
            
            // 2. 手势开始的时候,实例化,并设置相应的动作
            animator = UIViewPropertyAnimator(duration: 2.5, curve: .easeOut, animations: {
                self.circle.frame = self.circle.frame.offsetBy(dx: 100, dy: 0)
            })
            
            // 3. pauseAnimation, 动画未开始的时候, 会开启动画,并暂停
            animator?.pauseAnimation()
        case .changed:
            
            // 4. 手势 changed,改变 animator 的完成比
            let translation = recognizer.translation(in: circle)
            animator?.fractionComplete = translation.x / 100
            
        case .ended:
            
            // 5. 从 4 的完成比继续开始动画
            animator?.continueAnimation(withTimingParameters: nil, durationFactor: 0)
            
        default:
            break
        }
    }
```

值得一提的是,时间是如何计算呢?

以easyOut为例:用户交互是线性的,是动画进度来算的
当Progress = 0.5的时候,反应到时间曲线上,fractionComplete = 10% = 0.1;

image_1bqf22tongmsa5ml4penhk6j4b.png-721.6kB

那么剩余90%的time,fractionComplete = 0.1 来完成剩下动画的 50% Progress

image_1bqf2dhtt11e1lcvq8ttjibf758.png-323.5kB

2.2 Interruptible Animations(可中断动画)

var animator : UIViewPropertyAnimator!
    func animateTransitionIfNeeded(duration: TimeInterval) {
        if animator != nil {
            return
        }
        animator = UIViewPropertyAnimator(duration: duration, curve: .easeIn, animations: {
            self.circle.frame = self.circle.frame.offsetBy(dx: 300, dy: 0)
        })
        animator.startAnimation()
    }
    
    var progressWhenInterrupted : CGFloat = 0.0
    
    @objc func handlePan(recognizer: UIPanGestureRecognizer) {
        
        switch recognizer.state {
        case .began:
            animateTransitionIfNeeded(duration: 1)
            animator?.pauseAnimation()
            progressWhenInterrupted = animator.fractionComplete
            
        case .changed:
            let translation = recognizer.translation(in: circle)
            animator?.fractionComplete = translation.x / 100 + progressWhenInterrupted
            
        case .ended:
            let timing = UICubicTimingParameters(animationCurve: .easeOut)
            animator.continueAnimation(withTimingParameters: timing, durationFactor: 0)
    
        default:
            break
        }
    }
    

思路:
开启动画 -> 监听到手指之后,停止动画,记录动画的fractionComplete -> 手势Changed,改变动画的 fractionComplete -> 继续动画

Pause

  • 当Animator 执行动画开始,到 1 (time = 0.5, Progress = 10%) 的时候,用户手势进行了中断;
  • 用户交互是线性的,反应到了 2 (time = 0.1, progress = 0.1 因为线性的)的地方;

image_1bqf430d61qkl1lbg1n8m114qknu5l.png-481.1kB

Continue

  • 当用户松开之后,继续以 easyOut进行动画的时候,由 1 位置转变为 2 的位置, Progress = 10%
  • 2 位置此时对应的 time = 0.05, fractionComplete = 0.05, 也就是说,剩下 95%的时间来完成 剩下Progress = 90%的动画

Snip20170920_15.png-511.8kB


三、New Property Animator Behaviors: UIPropertyAnimator新的属性

  • scrubsLinearly
  • pausesOnCompletion.

3.1 scrubsLinearly

A Boolean value indicating whether a paused animation scrubs linearly or uses its specified timing information.
The default value of this property is true, which causes the animator to use a linear timing function during scrubbing. Setting the property to false causes the animator to use its specified timing curve.

简单的说: 这个参数就是,当你与动画进行交互时候,是按照线性的来做动画还是按照原来的时间曲线来做动画, true 表示利用线性的, false 表示利用指定的
例如: 动画开始是按照 easyIn的,用户进行交互时候,time curve 为线性的,

  • scrubsLinearly = true, 那么用户进行交互的时候,是按照线性的来改变;
  • scrubsLinearly = false, 那么就按照原来 easyIn的方式来。

3.2 pausesOnCompletion

A Boolean value that indicates whether a completed animation remains in the active state.
When the value of this property is true, the animator remains in the active state when the animation finishes, and it does not execute its completion handler. Keeping the animator in the active state allows you to reverse the animation even after it has finished. When the value of this property is false, the animator automatically transitions to the inactive state when the animation finishes, thereby concluding the animation. The default value of this property is false.
Because the completion handler is not called when this property is true, you cannot use the animator's completion handler to determine when the animations have finished running. Instead, you determine when the animation has ended by observing the isRunning property.

Animator的状态图(pausesOnCompletion = false )

  • 开始实例化出来,Animator 是 .Inactive状态
  • 当调用 startAnimation()pauseAnimation(), Animator进入active状态;
  • 动画结束,animator 再次进入 .Inactive 状态

image_1bqfa1lookj0b4o1jvp1hdfimns.png-171.6kB

Animator的状态图(pausesOnCompletion = true )

  • 开始实例化出来,Animator 是 .Inactive状态
  • 当调用 startAnimation()pauseAnimation(), Animator进入active状态;
  • 动画结束,animator 保持 active 状态

注意: 此时不会调用完成的回调, 观察是否动画完成,可以通过 isRunning属性

image_1bqfa8vpc4sn1qhvb7216vs1ul03s.png-125.8kB

posted @ 2017-12-01 20:45  洒水先生  阅读(194)  评论(0编辑  收藏  举报