开始一本正经的胡说八道,如有错误请包含,请指出。
物体的几种物理行为:
1. UIAttachmentBehavior 吸附固定行为
2. UICollisionBehavior 碰撞行为
3. UIGravityBehavior 重力行为
4. UIPushBehavior 推力行为
5. UISnapBehavior 甩行为(暂且这么叫)
UIAttachmentBehavior:
UIAttachmentBehavior的初始化方法有好几种,可以通过构造器也可以通过类方法,不外乎两大类型,物体和物体、物体和点之间。具体的可以看下文档。这里介绍下管于该类型的一些属性和简单的使用方法。
items:一个UIAttachmentBehavior对象所包含的物体
attachedBehaviorType:附属或者吸附行为的类型get类型在生成一个 UIAttachmentBehavior的对象时已经决定了,就是物体和物体之间的附属行为,或者物体和一个点之间的附属行为
length:两个物体之间的距离(或者是点和物体之间的距离)
damping:吸附还原时的阻力大小
frequency:震荡频率
frictionTorque:克服一个物体做圆周运动的力的大小
attachmentRange:吸附行为的运动范围
例子:
import UIKit
/** 吸附行为 */
class AttachViewController: UIViewController {
var attachButton = UIButton()
var animator = UIDynamicAnimator()
override func viewDidLoad() {
super.viewDidLoad()
title = "吸附行为"
view.backgroundColor = UIColor.darkGray
attachButton = UIButton(frame: CGRect(x: 100, y: 100, width: 50, height: 50))
attachButton.backgroundColor = UIColor.blue
view.addSubview(attachButton)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
showAttach()
}
func showAttach() {
animator = UIDynamicAnimator(referenceView: self.view)
animator.delegate = self
let attachBehavior = UIAttachmentBehavior(item: attachButton, attachedToAnchor: attachButton.center)
attachBehavior.length = 20
//设置吸附还原时的阻力系数大小
attachBehavior.damping = 0.1
//设置震荡频率
attachBehavior.frequency = 2.3
animator.addBehavior(attachBehavior)
//加一个推力 推力的类型有两种一种是瞬间的推力,一种是连续的 分别对应的是 instantaneous 和 continuous
let pushBehavior = UIPushBehavior(items: [attachButton], mode: .instantaneous)
//设置推力可用
pushBehavior.active = true
//设置力的方向
pushBehavior.pushDirection = CGVector(dx: 1, dy: 0)
//设置力的大小
pushBehavior.magnitude = 100
animator.addBehavior(pushBehavior)
}
}
extension AttachViewController : UIDynamicAnimatorDelegate {
func dynamicAnimatorDidPause(_ animator: UIDynamicAnimator) {
print("\(#function)")
}
}
UICollisionBehavior
只介绍属性,方法自己看
collisionMode:碰撞类型有三种items(物体和物体间的碰撞)、boundaries(物体和边界的朋转)、everything(不管什么)
translatesReferenceBoundsIntoBoundary:添加物理行为时,必须将这些物理行为添加到UIDynamicAnimator对象中,在创建UIDynamicAnimator对象时UIDynamicAnimator(referenceView: self.view)方法会指定一个UIView,translatesReferenceBoundsIntoBoundary属性就是是否碰撞边界为这个UIView的边界,之后只要添加到这个UIDynamicAnimator上的物理行为,都是发生在该UIView的坐标系统中。
import UIKit
/** 碰撞行为 */
class CollisionViewController: UIViewController {
var attachButton = UIButton()
var newButton = UIButton()
var animationer = UIDynamicAnimator()
override func viewDidLoad() {
super.viewDidLoad()
title = "碰撞行为"
view.backgroundColor = UIColor.darkGray
attachButton = UIButton(frame: CGRect(x: 100, y: 100, width: 50, height: 50))
attachButton.backgroundColor = UIColor.blue
view.addSubview(attachButton)
newButton = UIButton(frame: CGRect(x: 160, y: 100, width: 50, height: 50))
newButton.backgroundColor = UIColor.red
self.view.addSubview(newButton)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
collisionAnimation()
}
fileprivate func collisionAnimation() {
animationer = UIDynamicAnimator(referenceView: self.view)
//给物体一个力,这个力可以是重力,也可以是通过UIPushBehavior自定义的一个推力
let gBehavior = UIGravityBehavior(items: [attachButton])
gBehavior.gravityDirection = CGVector(dx: 0, dy: 1)
animationer.addBehavior(gBehavior)
let collisionBehavior = UICollisionBehavior(items: [attachButton])
collisionBehavior.translatesReferenceBoundsIntoBoundary = true
collisionBehavior.collisionMode = .everything
animationer.addBehavior(collisionBehavior)
}
}
UIGravityBehavior只介绍属性,方法自己看文档
gravityDirection:重力方向 是一个CGVector类型的结构体,(0,1)代表竖直向下,(0,-1)代表竖直向上,(1,0)水平向右。(-1,0)水平向左
angle: 力的角度
magnitude: 力的大小
class GravityViewController: UIViewController,UIDynamicAnimatorDelegate {
let ball = Ellipse()
let circile = UIView()
var animator = UIDynamicAnimator()
override func viewDidLoad() {
super.viewDidLoad()
title = "重力行为"
view.backgroundColor = UIColor.darkGray
// Do any additional setup after loading the view.
ball.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
ball.layer.cornerRadius = min(ball.bounds.size.width / 2, ball.bounds.size.height / 2)
ball.layer.masksToBounds = true
ball.backgroundColor = UIColor.blue
self.view.addSubview(ball)
circile.frame = CGRect(x: 10, y: 10, width: 10, height: 10)
circile.backgroundColor = UIColor.black
circile.layer.cornerRadius = min(circile.bounds.size.width / 2, circile.bounds.size.height / 2)
circile.layer.masksToBounds = true
ball.addSubview(circile)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
gravity()
}
func gravity() {
/*
注意**: 当只给物体添加一个重力行为时,物体是无限制下落的,尽管我们的屏幕尺寸只有那么大;
就好比一个物体从一个无限高的地方下落,永远都不会着地,所以下落也就不会结束。
dynamicAnimatorDidPause这个函数也不会运行.
所以在这里我给物体加一个碰撞边界
*/
animator = UIDynamicAnimator(referenceView: self.view)
animator.delegate = self
let gravityBehavior = UIGravityBehavior(items: [ball])
gravityBehavior.magnitude = 2
gravityBehavior.gravityDirection = CGVector(dx: 0, dy: 1)
gravityBehavior.angle = CGFloat(M_PI_4)
animator.addBehavior(gravityBehavior)
let colission = UICollisionBehavior(items: [ball])
colission.translatesReferenceBoundsIntoBoundary = true
colission.collisionMode = .everything
animator.addBehavior(colission)
let itemBehavior = UIDynamicItemBehavior(items: [ball])
itemBehavior.elasticity = 0.4
animator.addBehavior(itemBehavior)
}
func dynamicAnimatorDidPause(_ animator: UIDynamicAnimator) {
print("\(#function)")
}
func dynamicAnimatorWillResume(_ animator: UIDynamicAnimator) {
print("\(#function)")
}
}
class Ellipse: UIView {
override var collisionBoundsType: UIDynamicItemCollisionBoundsType {
return .ellipse
}
}
UIPushBehavior推力行为
mode:在初始话推力时要定义推力的类型,有两种类型continuous、instantaneous,分别是连续的力和瞬间的力
active: 当前推力是否可用
angle: 推力的角度
magnitude: 推力的大小
pushDirection:推理的方向和重力的方向一样
class PushViewController: UIViewController {
let ball = Ellipse()
let circile = UIView()
var animator = UIDynamicAnimator()
override func viewDidLoad() {
super.viewDidLoad()
title = "推动行为"
view.backgroundColor = UIColor.darkGray
ball.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
ball.layer.cornerRadius = min(ball.bounds.size.width / 2, ball.bounds.size.height / 2)
ball.layer.masksToBounds = true
ball.backgroundColor = UIColor.blue
self.view.addSubview(ball)
// Do any additional setup after loading the view.
circile.frame = CGRect(x: 10, y: 10, width: 10, height: 10)
circile.backgroundColor = UIColor.black
circile.layer.cornerRadius = min(circile.bounds.size.width / 2, circile.bounds.size.height / 2)
circile.layer.masksToBounds = true
ball.addSubview(circile)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
push()
}
func push() {
animator = UIDynamicAnimator(referenceView: self.view)
//推力在之前已经做过介绍,可以看碰撞行为的代码
let pushBehavior = UIPushBehavior(items: [ball], mode: .continuous)
pushBehavior.active = true
pushBehavior.magnitude = 1
pushBehavior.pushDirection = CGVector(dx: 0, dy: 1)
animator.addBehavior(pushBehavior)
let colission = UICollisionBehavior(items: [ball])
colission.translatesReferenceBoundsIntoBoundary = true
colission.collisionMode = .everything
animator.addBehavior(colission)
let itemBehavior = UIDynamicItemBehavior(items: [ball])
itemBehavior.elasticity = 0.4
itemBehavior.addAngularVelocity(-3, for: itemBehavior.items.first!)
animator.addBehavior(itemBehavior)
}
}
class Ellipse: UIView {
override var collisionBoundsType: UIDynamicItemCollisionBoundsType {
return .ellipse
}
}
UISnapBehavior甩行为
snapPoint: 将物体甩向这个点
damping:将物体甩向一个指定的点后,物体会震荡一会,damping为震荡系数,默认值为0.5,取值范围为0-1太大了的话可能看不到震荡效果
class SnapViewController: UIViewController {
let ball = Ellipse()
let circile = UIView()
var animator = UIDynamicAnimator()
override func viewDidLoad() {
super.viewDidLoad()
title = "迅速移动"
view.backgroundColor = UIColor.darkGray
ball.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
ball.layer.cornerRadius = min(ball.bounds.size.width / 2, ball.bounds.size.height / 2)
ball.layer.masksToBounds = true
ball.backgroundColor = UIColor.blue
self.view.addSubview(ball)
// Do any additional setup after loading the view.
circile.frame = CGRect(x: 10, y: 10, width: 10, height: 10)
circile.backgroundColor = UIColor.black
circile.layer.cornerRadius = min(circile.bounds.size.width / 2, circile.bounds.size.height / 2)
circile.layer.masksToBounds = true
ball.addSubview(circile)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
snap()
}
func snap() {
animator = UIDynamicAnimator(referenceView: self.view)
let snapBehavior = UISnapBehavior(item: ball, snapTo: CGPoint(x:UIScreen.main.bounds.size.width + 20,y:500))
//将物体甩向一个设定的点,停止在指定的点时,会震荡摇晃一会
snapBehavior.damping = 0.1
animator.addBehavior(snapBehavior)
}
}
extension AttachViewController : UIDynamicAnimatorDelegate {
func dynamicAnimatorDidPause(_ animator: UIDynamicAnimator) {
print("\(#function)")
}
}
最后的最后说说在添加这些物理属性时要注意的问题和UIDynamicItemBehavior:
因为说的时物理引擎,给物体加上一些物理属性,所以再给一些物体加上物理行为之后如碰撞、吸附时不要忘记给物体加一个力,重力或者一个自定义的推力,要不然物体怎么运动?
再给物体加上重力效果时,记得要加上一个碰撞边界要不然物体下落的这个过程永远执行不完。就好比从一个无限高的地方扔下一块石头,石头永远不会着地。
UIDynamicItemBehavior:可以给物体增加一些物理属性
elasticity:弹性系数
friction:摩擦力
density:密度
resistance:线性方向阻力
charge:代表能够影响一个元素在电磁场上如何移动的电荷(是的,听起来很疯狂) 网找的,不明白是什么鬼
isAnchored:本质上是将图形变成了碰撞中的一个静态物体,但没有响应事件(如果有什么东西撞上了它,它会丝毫不动),所以可以完美地用来表示地板或墙壁
angularResistance:角阻力,物体旋转时的阻力
allowsRotation:是否允许物体旋转
关于上面这些内容我写了个小Demo感觉有用的话不妨给个星。