UIDynamic
物理引擎UIDynamic简介
什么是UIDynamic?
UIDynamic是从iOS 7开始引入的一种新技术,隶属于UIKit框架。可以认为是一种物理引擎,能模拟和仿真现实生活中的物理现象,重力、弹性碰撞等现象
物理引擎的价值
广泛用于游戏开发,经典成功案例是“愤怒的小鸟”。让开发人员可以在远离物理学公式的情况下,实现炫酷的物理仿真效果。提高了游戏开发效率,产生更多优秀好玩的物理仿真游戏
使用步骤
- 创建一个物理仿真器(顺便设置仿真范围)
- 创建相应的物理仿真行为(顺便添加物理仿真元素)
- 将物理仿真行为添加到物理仿真器中 开始仿真
三大概念
物理仿真元素(Dynamic Item)
不是任何对象都能做物理仿真元素
不是任何对象都能进行物理仿真
哪些对象才能做物理仿真元素
任何遵守了UIDynamicItem协议的对象
UIView默认已经遵守了UIDynamicItem协议,因此任何UI控件都能做物理仿真
UICollectionViewLayoutAttributes类默认也遵守UIDynamicItem协议
物理仿真行为(Dynamic Behavior)
执行怎样的物理仿真效果?怎样的动画效果?
UIDynamic提供了以下几种物理仿真行为
UIGravityBehavior:重力行为
UICollisionBehavior:碰撞行为
UISnapBehavior:捕捉行为
UIPushBehavior:推动行为
物理仿真行为须知
上述所有物理仿真行为都继承自UIDynamicBehavior
所有的UIDynamicBehavior都可以独立进行
组合使用多种行为时,可以实现一些比较复杂的效果
物理仿真器(Dynamic Animator)
让物理仿真元素执行具体的物理仿真行为
物理仿真器须知
它可以让物理仿真元素执行物理仿真行为
它是UIDynamicAnimator类型的对象
UIDynamicAnimator的初始化
- (instancetype)initWithReferenceView:(UIView *)view;
view参数:是一个参照视图,表示物理仿真的范围
UIDynamicAnimator的常见方法
添加1个物理仿真行为
- (void)addBehavior:(UIDynamicBehavior *)behavior;
移除1个物理仿真行为
- (void)removeBehavior:(UIDynamicBehavior *)behavior;
移除之前添加过的所有物理仿真行为
- (void)removeAllBehaviors;
UIDynamicAnimator的常见属性
参照视图
@property (nonatomic, readonly) UIView* referenceView;
添加到物理仿真器中的所有物理仿真行为
@property (nonatomic, readonly, copy) NSArray* behaviors;
是否正在进行物理仿真
@property (nonatomic, readonly, getter = isRunning) BOOL running;
代理对象(能监听物理仿真器的仿真过程,比如开始和结束)
@property (nonatomic, assign) id <UIDynamicAnimatorDelegate> delegate;
常用行为演练
使用技巧:根据仿真元素创建仿真行为, 添加到仿真器即可执行该行为
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var box1: UIImageView!
@IBOutlet weak var box2: UIImageView!
lazy var animator: UIDynamicAnimator = {
return UIDynamicAnimator(referenceView: self.view)
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
view.backgroundColor = UIColor(patternImage: UIImage(named: "background")!)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let point = touches.first?.location(in: view)
snap(point: point!)
push()
gravity()
collision()
}
//重力行为(UIGravityAnimator)
//给定重力方向、加速度,让物体朝着重力方向掉落
func gravity() {
let behavior = UIGravityBehavior(items: [box1,box2])
animator.addBehavior(behavior)
}
//碰撞行为(UICollisionBehavior)
//可以让物体之间实现碰撞效果
//可以通过添加边界(boundary),让物理碰撞局限在某个空间中
func collision() {
let behavior = UICollisionBehavior(items: [box1,box2])
//边界碰撞
behavior.translatesReferenceBoundsIntoBoundary = true
/*
设置碰撞模式
public static var items: UICollisionBehaviorMode { get } //只碰撞元素
public static var boundaries: UICollisionBehaviorMode { get } //只碰撞边界
public static var everything: UICollisionBehaviorMode { get } //可以碰撞任何东西
*/
behavior.collisionMode = UICollisionBehaviorMode.everything
//设置内边距
behavior.setTranslatesReferenceBoundsIntoBoundary(with: UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20))
let startPoint = CGPoint(x:5,y:UIScreen.main.bounds.height * 0.5 + 200)
let endPoint = CGPoint(x: view.bounds.width - 5, y: view.bounds.height - 5)
behavior.addBoundary(withIdentifier: "line" as NSCopying, from: startPoint, to: endPoint)
//设置碰撞代理,监听碰撞情况
behavior.collisionDelegate = self
animator.addBehavior(behavior)
}
//捕捉行为(UISnapBehavior)
//可以让物体迅速冲到某个位置(捕捉位置),捕捉到位置之后会带有一定的震动
func snap(point:CGPoint) {
//如果想要多次执行捕捉行为,必须移除之前添加的捕捉行为
animator.removeAllBehaviors()
let behavior = UISnapBehavior(item: box2, snapTo: point)
animator.addBehavior(behavior)
}
//推动行为 (UIPushBehavior)
//可以向某个方向, 推动某个物体
func push() {
let behavior = UIPushBehavior(items: [box1,box2], mode: .instantaneous)
//设置推动的方向
behavior.pushDirection = CGVector(dx: 0, dy: -6)
animator.addBehavior(behavior)
}
}
extension ViewController : UICollisionBehaviorDelegate {
func collisionBehavior(_ behavior: UICollisionBehavior, beganContactFor item1: UIDynamicItem, with item2: UIDynamicItem, at p: CGPoint) {
print("开始碰撞,元素-元素")
}
func collisionBehavior(_ behavior: UICollisionBehavior, beganContactFor item: UIDynamicItem, withBoundaryIdentifier identifier: NSCopying?, at p: CGPoint) {
print("开始碰撞,元素-边界")
}
func collisionBehavior(_ behavior: UICollisionBehavior, endedContactFor item1: UIDynamicItem, with item2: UIDynamicItem) {
print("结束碰撞,元素-元素")
}
func collisionBehavior(_ behavior: UICollisionBehavior, endedContactFor item: UIDynamicItem, withBoundaryIdentifier identifier: NSCopying?) {
print("结束碰撞,元素-边界")
}
}