iOS - UIViewPropertyAnimator

UIViewPropertyAnimator

A class that animates changes to views and allows the dynamic modification of those animations.

UIViewPropertyAnimator是iOS10引入的新类,使用该类可以动态的修改views的动画

属性

@available(iOS 10.0, *)
open class UIViewPropertyAnimator : NSObject, UIViewImplicitlyAnimating, NSCopying {
    // 动画曲线
    @NSCopying open var timingParameters: UITimingCurveProvider? { get }

    // 动画时间
    open var duration: TimeInterval { get }

    // 默认为0,延时时间
    open var delay: TimeInterval { get }

    /// 默认 YES. 是否允许交互
    open var isUserInteractionEnabled: Bool
}

方法

  • 初始化方法(Initializing a Property Animator)
// 使用自定义动画曲线对象初始化Property Animator
public init(duration: TimeInterval,
       timingParameters parameters: UITimingCurveProvider)


/// 便捷构造方法
// 普通曲线动画方式
public convenience init(duration: TimeInterval,
                   curve: UIView.AnimationCurve,
                   animations: (() -> Void)? = nil)

// 定义贝塞尔动画曲线
public convenience init(duration: TimeInterval,
                   controlPoint1 point1: CGPoint,
                   controlPoint2 point2: CGPoint,
                   animations: (() -> Void)? = nil)

// 弹黄效果
public convenience init(duration: TimeInterval,
                   dampingRatio ratio: CGFloat,
                   animations: (() -> Void)? = nil)

// 该方法跟UIView的动画方法类似,根据需求填写参数
open class func runningPropertyAnimator(withDuration duration: TimeInterval,
                                        delay: TimeInterval,
                                        options: UIView.AnimationOptions = [],
                                        animations: @escaping () -> Void,
                                        completion: ((UIViewAnimatingPosition) -> Void)? = nil) -> Self   
  • UIViewImplicitlyAnimating
public protocol UIViewImplicitlyAnimating : UIViewAnimating {
    // 添加具体的动画闭包带延时
    optional public func addAnimations(_ animation: @escaping () -> Void, delayFactor: CGFloat)
    // 添加具体的动画闭包
    optional public func addAnimations(_ animation: @escaping () -> Void)

    @available(iOS 10.0, *) // 添加完成闭包
    optional public func addCompletion(_ completion: @escaping (UIViewAnimatingPosition) -> Void)

    optional public func continueAnimation(withTimingParameters parameters: UITimingCurveProvider?, 
                                           durationFactor: CGFloat)
}
  • UIViewAnimating
public protocol UIViewAnimating : NSObjectProtocol {

    @available(iOS 10.0, *)
    public var state: UIViewAnimatingState { get }

    // 动画是否正在运行
    public var isRunning: Bool { get }

    // 反转动画
    public var isReversed: Bool { get set }

    // 0-1,执行的进度
    public var fractionComplete: CGFloat { get set }

    // 开始动画
    public func startAnimation()

    // 指定延时之后开始动画
    public func startAnimation(afterDelay delay: TimeInterval)

    // 暂停动画
    public func pauseAnimation()

    // 停止动画,参数为true将变为inactive状态,否则是stopped状态
    public func stopAnimation(_ withoutFinishing: Bool)

    // 处于stopped状态被调用
    @available(iOS 10.0, *)
    public func finishAnimation(at finalPosition: UIViewAnimatingPosition)
}
  • UIViewAnimatingState(动画状态)
animation_states_2x_6526d868-7211-4cbd-b7e1-aadfb0127310.png
@available(iOS 10.0, *)
public enum UIViewAnimatingState : Int {
    case inactive // The animation is not executing.
    case active   // The animation is executing.
    case stopped // The animation has been stopped and has not transitioned to inactive.
}
  • 当动画开始或者暂停的时候,动画状态为 active

  • 当控件被创建出来且没有开始执行动画或者已经执行完动画的时候,它的状态是 inactive

  • 当动画执行完毕或者使用 stop 命令暂停动画后,控件的状态变为 stopped

  • UIViewAnimatingPosition(动画位置)

@available(iOS 10.0, *)
public enum UIViewAnimatingPosition : Int {
    case end
    case start
    case current
}

实战

体验初始化方法

  • 常用动画方式
 func moveAnimation(_ point: CGPoint) {
     let animator = UIViewPropertyAnimator(duration: 1.0, curve: .easeInOut) {
         self.redView.center = point
     }
     animator.startAnimation()
 }
2018-11-30 16-10-30.2018-11-30 16_10_40.gif

如果想延时动画,使用下面方法

animator.startAnimation(afterDelay: 3.0)
  • 弹性动画
 func springAnimation(_ point: CGPoint) {
     let animator = UIViewPropertyAnimator(duration: 1.0, dampingRatio: 0.4) {
          self.redView.center = point
      }
     animator.startAnimation()
 }
2018-11-30 16-12-24.2018-11-30 16_12_35.gif
  • 自定义动画曲线

方式一

 func customCurveAnimation(_ point: CGPoint) {
     let animator = UIViewPropertyAnimator(duration: 1.0,
                                           controlPoint1: CGPoint(x: 0.1, y: 0.5),
                                           controlPoint2: CGPoint(x: 0.5, y: 0.2)) {
                                               self.redView.center = point
      }
     animator.startAnimation()
 }

方式二

  func cubicAnimation(_ point: CGPoint) {
      let cubicTiming = UICubicTimingParameters(controlPoint1: CGPoint(x: 0.1, y: 0.5), 
                                                controlPoint2: CGPoint(x: 0.5, y: 0.2))
      let animator = UIViewPropertyAnimator(duration: 1.0, timingParameters: cubicTiming)
      animator.addAnimations {
          self.redView.center = point
      }
      animator.startAnimation()
  }
2018-11-30 16-14-25.2018-11-30 16_14_54.gif
  • 类方法动画
 func classAnimator(_ point: CGPoint) {
        // 动画立即开始
        let animator = UIViewPropertyAnimator
            .runningPropertyAnimator(withDuration: 1.0,
                                     delay: 0.0,
                                     options: [],
                                     animations: {
                                        self.redView.center = point },
                                     completion: { position in
                                        print(position) })
  }
2018-11-30 16-44-53.2018-11-30 16_45_02.gif

使用该方法创建的动画会立马执行,返回的animator可以根据需求进行设置。动画完成执行闭包,得到动画的最终position,使用该值能够确定动画是在begin, end还是其他位置停止的。

相关功能

  • 添加动画
 func addAnimations(_ point: CGPoint) {
      // 位置
      let animator = UIViewPropertyAnimator(duration: 1.0, curve: .easeIn) {
           self.redView.center = point
      }
      // 透明度
      animator.addAnimations {
          self.redView.alpha = 0.2
      }
      // 缩放
      animator.addAnimations {
          self.redView.transform = CGAffineTransform(scaleX: 0.2, y: 0.2)
      }
      animator.startAnimation()
  }
2018-11-30 16-21-33.2018-11-30 16_21_43.gif

可以看到动画是同时执行的,因为默认的状态的inactive,所以多个动画闭包同时执行。如果是在动画的过程中添加动画,那么将会在剩余的时间内执行对应的动画

  • 添加完成闭包

可以在动画完成之后执行某些结束操作

  func addCompletion(_ point: CGPoint) {
        let animator = UIViewPropertyAnimator(duration: 1.0, curve: .easeIn) {
            self.redView.center = point
        }
        animator.addAnimations {
            self.redView.alpha = 0.2
        }
        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")
            }
        }
        animator.startAnimation()
    }

动画执行结束,打印

Completion handler called at end of animation
  • 控制进度
  func scrubAnimation() {
      let animtor = UIViewPropertyAnimator(duration: 5.0, curve: .easeIn) {
          self.redView.frame = CGRect(x: 300, y: 150, width: 100, height: 50)
      }
      self.animator = animtor
      // 添加滑动条
      let scrubber = UISlider(frame: CGRect(x: 50, y: 100, width: 300, height: 20))
      scrubber.addTarget(self, action: #selector(slideEvent(_:)), for: .valueChanged)
      view.addSubview(scrubber)
  }

  @objc func slideEvent(_ slider: UISlider) {
      self.animator.fractionComplete = CGFloat(slider.value)
  }
2018-11-30 17-20-40.2018-11-30 17_20_58.gif
  • 反转动画

在动画的执行过程中,返回最初的状态

func reverseAnimations(_ point: CGPoint) {
    let animator = UIViewPropertyAnimator(duration: 1.0, curve: .easeIn) {
          self.redView.center = point
     }
    self.animator = animator
    animator.startAnimation()
 }

 @objc func buttonClicked() {
      self.animator.isReversed = true
 }
2018-11-30 17-36-30.2018-11-30 17_36_44.gif

参考

UIViewPropertyAnimator
iOS 10 Day by Day :: Day 4 :: UIViewPropertyAnimator

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明AI阅读 16,025评论 3 119
  • 蓝的天,白的云,红的花,绿的树,走的我,笑的你。
    莫问星光阅读 167评论 2 0
  • 你只听你想听的我只说我想说的交流毫无意义 如果你只观注你我只观注我那么世界是孤独的 后来你学会了倾听我学会了思考再...
    瑜伽散人阅读 255评论 1 5
  • 转自http://blog.sunnyxx.com/archives/page/4/ 我们很熟悉char这个数据类...
    小黄人写代码阅读 1,041评论 0 49
  • 终有一天我变得不再喜怒形于色,不再随时随处总想牵着一个人的手,不再逢人便掏心掏肺,你说是因为我变成熟了……不,我微...
    一蓑烟雨_886阅读 128评论 0 0