基本概念
Apple定义了behavior类(iOS7 and up),可以很容易的实现重力,碰撞等特效。
-UICollisionBehavior: 提供碰撞检测
-UIGravityBehavior:重力
-UIPushBehavior:可以在你的view上模拟推的动作,比如:把你的手指放在屏幕上,推动一个小方块
-UISnapBehavior: 把一个view sanp到一个点上
对每一个动态behavior,都需要attach到一个animator(UIDynamicAnimator),而animator使用reference view的坐标系统。
5.1 添加重力
步骤:
- 初始化一个UIGravityBehavior;
- 添加它到你的UI component上;
- 创建一个UIDynamicAnimator;
- 把UIGravityBehavior添加到animator上;
var squareView: UIView?
var animator: UIDynamicAnimator?
override func viewDidLoad() {
super.viewDidLoad()
squareView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
if let theSquareView = squareView {
theSquareView.backgroundColor = UIColor.greenColor()
theSquareView.center = view.center
view.addSubview(theSquareView)
animator = UIDynamicAnimator(referenceView: view)
if let theAnimator = animator {
let gravity = UIGravityBehavior(items: [theSquareView])
theAnimator.addBehavior(gravity)
}
}
}
5.2 再添加碰撞检测
//以view的bounds作为拦截线
collision.translatesReferenceBoundsIntoBoundary = true
自定义拦截线
let bottomBoundary = "bottomBoundary"
let fromPoint = CGPoint(x: 0, y: view.bounds.height - 100)
let toPoint = CGPoint(x: view.bounds.width, y: view.bounds.height - 100)
collision.addBoundaryWithIdentifier(bottomBoundary, fromPoint:fromPoint, toPoint:toPoint)
UICollisionBehaviorDelegate:
- beganContactForItem: item开始碰撞
- endedContactForItem:item结束碰撞
func collisionBehavior(behavior: UICollisionBehavior, beganContactForItem item: UIDynamicItem, withBoundaryIdentifier identifier: NSCopying, atPoint p: CGPoint) {
if identifier as? String == bottomBoundary {
UIView.animateWithDuration(1, animations: { () -> Void in
let view = item as! UIView
view.backgroundColor = UIColor.redColor()
view.alpha = 0
view.transform = CGAffineTransformMakeScale(2, 2)
}, completion: { (finished:Bool) -> Void in
let view = item as! UIView
behavior.removeItem(item)
view.removeFromSuperview()
})
}
}
collision.collisionDelegate = self
collisionMode的属性:
-UICollisionBehaviorModeItems: 会检测动态item之间的碰撞
-UICollisionBehaviorModeBoundaries: 检测动态item和boundary之间的碰撞
-UICollisionBehaviorModeEverything:检测所有碰撞,这个是缺省值
collision.collisionMode = UICollisionBehaviorMode.Items
5.3 Push (UIPushBehavior)
给被操纵物体一个push或pull的力,加速度恒定
步骤:
- 用initWithItems:mode:做初始化,生成一个UIPushBehavior对象,
- 其中mode使用UIPushBehaviorModeContinuous,
- 然后要用setAngle,设置角度,角度的计算单位是radian,也就是π,
- 然后要用setMagnitude,设置加速度等级,每一个单位是100/s2
角度的计算实际是计算斜率,公式:tanα=(y2-y1)/(x2-x1),如果想从点1到点2方向产生一个力,那么公式的第一个点是点1,第二个点是点2.
let deltaX = tapPoint.x - squareViewCenterPoint.x
let deltaY = tapPoint.y - squareViewCenterPoint.y
let angle = atan2(deltaY, deltaX)
pushBehavior!.angle = angle
Magnitude的计算:
let distanceBetweenPoints = sqrt(pow(deltaX, 2.0) + pow(deltaY, 2.0))
pushBehavior!.magnitude = distanceBetweenPoints / 300.0
实现手指点一下,正方形就飞向手指点的位置的动画:
class ViewController: UIViewController {
var squareView: UIView?
var animator: UIDynamicAnimator?
var pushBehavior: UIPushBehavior?
override func viewDidLoad() {
super.viewDidLoad()
createGestureRecognizer()
createSmallSquareView()
createAnimatorAndBehaviors()
}
func createSmallSquareView() {
squareView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
if let theSquareView = squareView {
theSquareView.backgroundColor = UIColor.greenColor()
theSquareView.center = view.center
view.addSubview(theSquareView)
}
}
func createGestureRecognizer() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: "handleTap:")
view.addGestureRecognizer(tapGestureRecognizer)
}
func createAnimatorAndBehaviors() {
animator = UIDynamicAnimator(referenceView: view)
if let theSquareView = squareView {
let collision = UICollisionBehavior(items: [theSquareView])
collision.translatesReferenceBoundsIntoBoundary = true
pushBehavior = UIPushBehavior(items: [theSquareView], mode: UIPushBehaviorMode.Continuous)
animator!.addBehavior(collision)
animator!.addBehavior(pushBehavior)
}
}
func handleTap(tap: UITapGestureRecognizer) {
let tapPoint = tap.locationInView(view)
let squareViewCenterPoint = self.squareView!.center
//angle是斜率, 公式: tanα=(y2-y1)/(x2-x1)
// 因为是想产生从squareView到tapPoint的力,所以tapPoint是第二个点
let deltaX = tapPoint.x - squareViewCenterPoint.x
let deltaY = tapPoint.y - squareViewCenterPoint.y
let angle = atan2(deltaY, deltaX)
pushBehavior!.angle = angle
//两点之间的距离
let distanceBetweenPoints = sqrt(pow(deltaX, 2.0) + pow(deltaY, 2.0))
pushBehavior!.magnitude = distanceBetweenPoints / 300.0
}
}
5.4 UIAttachmentBehavior
attachment behavior可以让绿色的方块跟随红色方块运动,以棕色的方块为锚点(Anchor)。
attachmentBehavior = UIAttachmentBehavior(item: greenView, offsetFromCenter: UIOffset(horizontal: 30, vertical: -40), attachedToAnchor: redView.center)
方块跟随手指运动需要用panGestureRecognizer:
func createGestureRecognizer() {
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: "handlePan:")
view.addGestureRecognizer(panGestureRecognizer)
}
func createAnimatorAndBehaviors() {
animator = UIDynamicAnimator(referenceView: view)
let collision = UICollisionBehavior(items: [squareView])
collision.translatesReferenceBoundsIntoBoundary = true
attachmentBehavior = UIAttachmentBehavior(item: squareView, offsetFromCenter: UIOffset(horizontal: 30, vertical: -40), attachedToAnchor: anchorView.center)
animator?.addBehavior(collision)
animator?.addBehavior(attachmentBehavior)
}
func handlePan(pan: UIPanGestureRecognizer) {
let tapPoint = pan.locationInView(view)
attachmentBehavior?.anchorPoint = tapPoint
anchorView.center = tapPoint
}
5.5 Snap Effect
有一种果冻颤抖的效果。
下列程序是方块跟着手走,而且有颤抖效果。
初始化函数是:
UISnapBehavior(item: squareView, snapToPoint: panPoint)
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.createSmallSquareView()
self.createGestureRecognizer()
self.createAnimatorAndBehaviors()
}
func createGestureRecognizer() {
let pan = UIPanGestureRecognizer(target: self, action: "handleTap:")
view.addGestureRecognizer(pan)
}
func createSmallSquareView() {
squareView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
squareView.backgroundColor = UIColor.greenColor()
squareView.center = view.center
view.addSubview(squareView)
}
func handlePan(pan:UIPanGestureRecognizer) {
let panPoint = pan.locationInView(view)
if let theSnap = snapBehavior {
animator.removeBehavior(theSnap)
}
snapBehavior = UISnapBehavior(item: squareView, snapToPoint: panPoint)
snapBehavior.damping = 0.5
animator.addBehavior(snapBehavior)
}
UIDynamicItemBehavior
参数:
- allowsRotation: 是否容许旋转
- resistance:阻力,范围是0 到CGFLOAT_MAX,值越大,阻力越大
- friction:摩擦力,范围从0.0 到1.0定义在舞台的每一条边有多少摩擦
- elasticity: 弹性,范围从0.0 到1.0, 缺省是0
- density:密度,范围从0 到1 (缺省是1),用于animator计算物体重量
初始化:
animator = UIDynamicAnimator(referenceView: view)
let gravity = UIGravityBehavior(items: [topView, bottomView])
animator.addBehavior(gravity)
let collision = UICollisionBehavior(items: [topView, bottomView])
collision.translatesReferenceBoundsIntoBoundary = true
animator.addBehavior(collision)
let moreElasticItem = UIDynamicItemBehavior(items: [bottomView])
moreElasticItem.elasticity = 1
let lessElasticItem = UIDynamicItemBehavior(items: [topView])
lessElasticItem.elasticity = 0.5
animator.addBehavior(moreElasticItem)
animator.addBehavior(lessElasticItem)