如何使用iOS 10的UIViewPropertyAnimator做动画

JesGroves 7年前
   <p>iOS 10 带来了一大票有意思的很特性,像 UIViewPropertyAnimator,它是一个改善动画处理的全新的类。 这个视图属性动画完全颠覆了我们已经习惯的流程,能够为动画逻辑添加更精细的控制。</p>    <p>一个简单的动画</p>    <p>让我们来看看如何通过一个简单的动画改变视图的中心点属性。</p>    <pre>  <code class="language-objectivec">let animator = UIViewPropertyAnimator(duration: 1.0, curve: .easeOut){      AView.center = finalPoint  }  animator.startAnimation()</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/9402e21692fea05556997c972cd54516.gif"></p>    <p>至少有3点需要注意:</p>    <p>1) 这个动画是通过闭包来定义的,与UIView 动画类的“UIView.animation(duration:…)”很相似。</p>    <p>2) 返回一个对象,即动画创建者。</p>    <p>3)这个动画不是立刻开始的,而是通过 `startAnimation()`方法触发的。</p>    <p><strong>动画状态</strong></p>    <p>我们对一个元素执行动画操作方式的主要变化与以下事实有关:一个属性动画器包含一整套状态机逻辑。通过`UIViewAnimating`协议实现的功能以一种简单明了的方式管理动画的状态,而这些状态又是通过`startAnimation`, `pauseAnimation` 和 `stopAnimation`函数来实现的。调用这些方法我们可以更新状态的值,使之能在`active`,`inactive`和`stopped`之间转换。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/8272c2851679602d0c5a8d89a56b428a.png"></p>    <p>当动画开始或者暂停时,动画的状态就是`活跃状态`;当动画已被初始化但是还未开始或者动画已完成,它就是`非活跃状态`。需要注意的是 在`非活跃状态`和`停止态`之间有一点点不同。当动画因停止命令而完成或者它真的已经完成后,状态会变成`停止态`,动画器内部会调用方法`finishAnimation(at:)` 来标记动画 已完成,将状态设置为`非活跃状态`,并最终调用完成的代码块。</p>    <p><strong>动画的可选项</strong></p>    <p>可能你已经在前面的例子里注意到,和动画的 block一起,我们定义了两个参数:动画时长和动画曲线,一个UIViewAnimationCurve实例,代表着最常见的曲线(easeIn,easeOut,linear或easeInOut)。 </p>    <p>如果想获得对动画曲线的更多控制,你可以使用由两个控制点定义的贝塞尔曲线。</p>    <pre>  <code class="language-objectivec">let animator = UIViewPropertyAnimator(                 duration: 1.0,                  point1: CGPoint(0.1,0.5),                  point2: CGPoint(0.5, 0.2){             AView.alpha = 0.0  }</code></pre>    <p><img src="https://simg.open-open.com/show/1c8eda35f7aaaea4fbda63c5363354f7.gif"></p>    <p>(如果一条贝塞尔曲线依然不够,你甚至可以使用[ UITimigCurveProvider ]来指定一条完全自定义的曲线)</p>    <p>另一个可以传给构造器的有意思的参数是 阻尼系数值。用法与UIView 的动画方法类似,你可以定义出弹簧效果,阻尼系数的取值范围是0到1.</p>    <pre>  <code class="language-objectivec">let animator = UIViewPropertyAnimator(                 duration: 1.0,                 dampingRatio:0.4){             AView.center = CGPoint(x:0, y:0)  }</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/7449e139c3e036e610536ef8ca9ffaad.gif"></p>    <p>延迟动画的执行也非常简单,只需要调用带有`afterDelay`参数的`startAnimation`方法即可。</p>    <pre>  <code class="language-objectivec">animator.startAnimation(afterDelay:2.5)</code></pre>    <p><strong>动画的block</strong></p>    <p>`UIViewPropertyAnimator` 采用的是能够为动画器提供很多有趣能力的`UIViewImplicitlyAnimating`协议。例如,除了在初始化的时候指定的block外,你还可以指定多个动画block。</p>    <pre>  <code class="language-objectivec">// Initialization  let animator = UIViewPropertyAnimator(duration: 2.0, curve: .easeOut){      AView.alpha = 0.0  }  // Another animation block  animator.addAnimation{       Aview.center = aNewPosition  }  animator.startAnimation()</code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/765484c2dbb9f8377479574bf792922a.gif"></p>    <p>你还可以向运行中的动画添加动画块,该动画块将立即使用剩余时间作为新动画的持续时间来执行。</p>    <p><strong>与动画流交互</strong></p>    <p>正如我们已提过的那样,我们可以通过调用`startAnimation`, `pauseAnimation` 和 `stopAnimation`轻松地与动画流交互。动画的默认流(从起始点到结束点),可以通过`fractionComplete`属性更改。这个值表示动画完成的百分比,取值范围是0 到 1。你能够修改这个值来像你期望的那样驱动流(例如:用户可能会用滑块或滑动手势实时地修改`fraction`)。</p>    <pre>  <code class="language-objectivec">animator.fractionComplete = slider.value</code></pre>    <p>某些情形下,你可能希望在动画运行完毕时执行一些操作。 `addCompletion` 方法能让你添加一个(当动画完成时会被触发的)代码块。</p>    <pre>  <code class="language-objectivec">animator.addCompletion { (position) in      print("Animation completed")  }</code></pre>    <p>`position`参数是一个 `UIViewAnimatingPosition`类型的值,它有三个枚举值,分别代表动画是在开始停止,结束后停止,还是当前位置停止。 通常你都会收到结束的枚举值。</p>    <p>(译者注:`UIViewAnimatingPosition`的三个枚举值分别是`end`,`start`,`current`)</p>    <p>这就是这份快速指南的全部内容啦。</p>    <p> </p>    <p> </p>    <p>来自:http://www.cocoachina.com/ios/20161130/18226.html</p>    <p> </p>