iOS动画:UIViewPropertyAnimator动画(14)

UIViewPropertyAnimator是在iOS10引入的,它解决了能够创建易于交互,可中断和/或可逆的视图动画的需求。
现在有这样一个场景LockScreenViewController.swift,让中间tableview放大显示
image_1
先设置tableView初始状态

  override func viewWillAppear(_ animated: Bool) {
    tableView.transform = CGAffineTransform(scaleX: 0.67, y: 0.67)
    tableView.alpha = 0
  }

此时tableView已经被隐藏,然后在viewDidAppear中添加动画

  override func viewDidAppear(_ animated: Bool) {
    let scale = UIViewPropertyAnimator(duration: 0.33, curve: .easeIn)
    scale.addAnimations {
      self.tableView.alpha = 1.0
    }
    scale.addAnimations({
      self.tableView.transform = .identity
    }, delayFactor: 0.33)
    scale.addCompletion { (_) in
      print("ready")
    }
    scale.startAnimation()
  }

这里要介绍一下delayFactor,它并不是我们前面学习到的delay延迟多少秒,它是延迟剩余时间的百分比执行,取值在0.0-1.0,什么意思呢?比如动画总时长为3秒,已经执行了1秒,还有2秒未执行,如果delayFactor是0.33,那么动画将在此刻延迟2*0.33秒执行。
你可以在每个addAnimations(_:)后添加scale.addCompletion,那么动画将一个接一个的执行。
最后我们需要启动动画

    scale.startAnimation()

运行效果
image_2
我们将代码封装一下,创建新的类AnimatorFactory.swift

import UIKit

class AnimatorFactory {
  static func scaleUp(view: UIView) -> UIViewPropertyAnimator {
    let scale = UIViewPropertyAnimator(duration: 0.33,
                                       curve: .easeIn)
    scale.addAnimations {
      view.alpha = 1.0
    }
    scale.addAnimations({
      view.transform = CGAffineTransform.identity
    }, delayFactor: 0.33)
    scale.addCompletion {_ in
      print("ready")
    }
    return scale
  }
}

替换viewDidLoad

  override func viewDidAppear(_ animated: Bool) {
    AnimatorFactory.scaleUp(view: tableView).startAnimation()
  }

如果是运行单个动画而不需要交互,那么你可以继续使用之前学习的UIView.animate(withDuration:…),当然UIViewPropertyAnimator也有对应的动画API。
在LockScreenViewController.swift中添加代码:

  func toggleBlur(_ blurred: Bool) {
    UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 0.5, delay: 0.1, options: .curveEaseOut, animations: {
      self.blurView.alpha = blurred ? 1 : 0
    }, completion: nil)
  }

在UISearchBarDelegate代理方法中调用

extension LockScreenViewController: UISearchBarDelegate {
  func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
    toggleBlur(true)
  }
  func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
    toggleBlur(false)
  }
  func searchBarResultsListButtonClicked(_ searchBar: UISearchBar) {
    searchBar.resignFirstResponder()
  }
  func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    if searchText.isEmpty {
      searchBar.resignFirstResponder()
    }
  }
}

运行效果
image_3

控制关键帧动画

继续使用AnimatorFactory.swift,添加新的方法:

  @discardableResult
  static func jiggle(view: UIView) -> UIViewPropertyAnimator {
    return UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 0.33, delay: 0, animations: {
      UIView.animateKeyframes(withDuration: 1, delay: 0, animations: {
        UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.25, animations: {
          view.transform = CGAffineTransform(rotationAngle: -.pi/8)
        })
        UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.75, animations: {
          view.transform = CGAffineTransform(rotationAngle: +.pi/8)
        })
        UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 1.0, animations: {
          view.transform = CGAffineTransform.identity
        })
      }, completion: nil)
    }, completion: { (_) in
      view.transform = .identity
    })
  }

当在外层添加UIViewPropertyAnimator的方法时,会中断或者延长UIView.animateKeyframes的执行时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值