第二个作业要求,先来看看吧,很有趣的一些动画效果
看要求,a和b都不是很麻烦,之前博主自学的时候接触过,第三个接触不多,老师上课时演示的时候有点着迷了,因为,如果有了这个UIDynamicAnimator,那么愤怒的小鸟就不是很难实现的游戏了(有这么神么?后面再介绍吧)
关于UIDynamicAnimator,CSDN的前辈写得很不错
先来看看第一个用animation实现视图位置、大小、转换的改变吧。其实代码很少,只需要调用UIView的工厂方法即可
func animation() {
let view = UIView(frame: CGRect(x: 300, y: 100, width: 100, height: 100))
view.backgroundColor = UIColor.orange
self.view.addSubview(view)
UIView.animate(withDuration: 3, delay: 0, options: [.repeat, .autoreverse], animations: {
view.frame = CGRect(x: 0, y: 20, width: 10, height: 10)
view.backgroundColor = UIColor.yellow
view.transform = view.transform.rotated(by: CGFloat.pi)
}, completion: nil)
}
我们先创建了一个视图,然后调用UIView的animate方法,这个方法有几种,我选择的是这个有5个参数的方法,其中第一个参数设置整个动画完成所需要的时间;第二个参数设置延迟多少秒之后将该动画加入线程队列中(所以真正开始执行动画的时间可能会有一些微妙的延迟);第三个是一些动画的参数选项,参数很多,可以使用数组来搭配,博主这里选择了重复和自动倒转;第四个参数设置动画的内容,我们只需要设置在动画结束那一个时刻的视图的状态,中间的过渡Swift会帮你计算;最后一个参数是动画整体完成之后的一些设置了。
这个动画效果就是一个视图从一个位置移动到另一个位置,并在移动的过程中从橙色变为黄色,并且大小改变的同时旋转。
然后是第二个用transition实现两个视图切换了。这时我们需要先声明两个UIView的属性
var firstView: UIView!
var secondView: UIView!
然后初始化这两个UIView并添加一个开始动画的按钮
func transition() {
let btn = UIButton(frame: CGRect(x: 0, y: 300, width: 100, height: 44))
btn.setTitle("切换视图", for: .normal)
btn.setTitleColor(UIColor.black, for: .normal)
btn.addTarget(self, action: #selector(changeView), for: .touchUpInside)
self.view.addSubview(btn)
firstView = UIView(frame: CGRect(x: 100, y: 300, width: 100, height: 100))
firstView.backgroundColor = UIColor.purple
self.view.addSubview(firstView)
secondView = UIView(frame: CGRect(x: 100, y: 300, width: 100, height: 100))
secondView.backgroundColor = UIColor.brown
self.view.addSubview(secondView)
}
最后实现动画的执行
@objc func changeView() {
UIView.transition(from: secondView, to: firstView, duration: 3, options: [.transitionCurlUp], completion: nil)
}
UIView 的transition方法与animate方法类似,在这里就不过多赘述了。不过这个动画的执行会与最开始的接触有点不同,博主在这里设置了动画是向上卷曲翻页,但这个翻页的动画不是在firstView和secondView的范围内,而是在他们两个的父视图上执行。
最后是UIDynamicAnimator了,这个我称之为力学动画,因为其中可以模拟现实世界的一些力学规律,比如物体受重力的作用、物体间的碰撞、物体受持续的推力或瞬时的推力、物体受吸附力、物体之间或物体与锚点之间的作用力。
我们在使用UIDynamicAnimator时,需要有三个东西
UIDynamicAnimator
UIDynamicBehavior(用其子类)
UIDynamicItem(UIView及其子类都是)
首先我们需要声明或初始化三个属性
var animator: UIDynamicAnimator!
var gravity = UIGravityBehavior()
var collision = UICollisionBehavior()
UIGravityBehavior为重力的行为,UICollisionBehavior为碰撞的行为
然后我们在方法中就可以随机产生一些视图添加到里面了
func dynamicAnimation() {
animator = UIDynamicAnimator(referenceView: self.view)
animator.addBehavior(gravity)
animator.addBehavior(collision)
collision.translatesReferenceBoundsIntoBoundary = true
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { (t) in
let x = CGFloat(arc4random() % (UInt32(self.view.frame.width) - 50))
let view = UIView(frame: CGRect(x: x, y: 20, width: 50, height: 50))
view.backgroundColor = UIColor.red
view.layer.borderWidth = 1
view.layer.cornerRadius = 10
self.view.addSubview(view)
self.gravity.addItem(view)
self.collision.addItem(view)
}
}
我们在初始化UIDynamicAnimator时传入了一个参考的视图,这个参考视图是用于确定UIDynamicAnimator的参考坐标系的。然后我们设置了UICollisionBehavior的translatesReferenceBoundsIntoBoundary,这个设置为真,就是将参考视图的边界作为碰撞的边界,在这个边界中的Item碰到边界时会有碰撞效果产生。
最后我们来看看最终的效果吧(虽然布局很乱,元素很杂,但是效果是有的)
最后贴上所有的代码吧
import UIKit
class ViewController: UIViewController {
var firstView: UIView!
var secondView: UIView!
var animator: UIDynamicAnimator!
var gravity = UIGravityBehavior()
var collision = UICollisionBehavior()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
animation()
transition()
dynamicAnimation()
}
func animation() {
let view = UIView(frame: CGRect(x: 300, y: 100, width: 100, height: 100))
view.backgroundColor = UIColor.orange
self.view.addSubview(view)
UIView.animate(withDuration: 3, delay: 0, options: [.repeat, .autoreverse], animations: {
view.frame = CGRect(x: 0, y: 20, width: 10, height: 10)
view.backgroundColor = UIColor.yellow
view.transform = view.transform.rotated(by: CGFloat.pi)
}, completion: nil)
}
func transition() {
let btn = UIButton(frame: CGRect(x: 0, y: 300, width: 100, height: 44))
btn.setTitle("切换视图", for: .normal)
btn.setTitleColor(UIColor.black, for: .normal)
btn.addTarget(self, action: #selector(changeView), for: .touchUpInside)
self.view.addSubview(btn)
firstView = UIView(frame: CGRect(x: 100, y: 300, width: 100, height: 100))
firstView.backgroundColor = UIColor.purple
self.view.addSubview(firstView)
secondView = UIView(frame: CGRect(x: 100, y: 300, width: 100, height: 100))
secondView.backgroundColor = UIColor.brown
self.view.addSubview(secondView)
}
@objc func changeView() {
UIView.transition(from: secondView, to: firstView, duration: 3, options: [.transitionCurlUp], completion: nil)
}
func dynamicAnimation() {
animator = UIDynamicAnimator(referenceView: self.view)
animator.addBehavior(gravity)
animator.addBehavior(collision)
collision.translatesReferenceBoundsIntoBoundary = true
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { (t) in
let x = CGFloat(arc4random() % (UInt32(self.view.frame.width) - 50))
let view = UIView(frame: CGRect(x: x, y: 20, width: 50, height: 50))
view.backgroundColor = UIColor.red
view.layer.borderWidth = 1
view.layer.cornerRadius = 10
self.view.addSubview(view)
self.gravity.addItem(view)
self.collision.addItem(view)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}