Reputation: 45
I'm doing a simple animation which requires me to handle some collisions with boundaries.
I have a class, viewcontroller, which I extend to be a UICollisionBehaviorDelegate so I can recognize and handle view collisions.
For some reason, when a collision happens, my delegate methods never fire.
class ViewController: UIViewController {
var fallingImageViews: [UIImageView]!
var downAnimator: UIDynamicAnimator!
override func viewDidLoad() {
super.viewDidLoad()
//imagine fallingImageViews Initializers happening here
downAnimator = initializeAnimators()
}
func initializeAnimators() -> UIDynamicAnimator {
let downwardAnimator = UIDynamicAnimator(referenceView: self.view)
downwardAnimator.addBehavior(setBoundaries())
downwardAnimator.addBehavior(setGravity())
downwardAnimator.addBehavior(setBounciness())
downwardAnimator.delegate = self
return downwardAnimator
}
func setBoundaries() -> UICollisionBehavior {
let boundaries = UICollisionBehavior(items: fallingImageViews)
boundaries.collisionDelegate = self
// prevent collisions between items
boundaries.collisionMode = .boundaries
boundaries.setTranslatesReferenceBoundsIntoBoundary = true
return boundaries
}
}
// MARK: Collision Behavior Delegate
extension ViewController: UICollisionBehaviorDelegate, UIDynamicAnimatorDelegate {
func collisionBehavior(_ behavior: UICollisionBehavior, endedContactFor item: UIDynamicItem, withBoundaryIdentifier identifier: NSCopying?) {
print(identifier)
}
func collisionBehavior(_ behavior: UICollisionBehavior, beganContactFor item: UIDynamicItem, withBoundaryIdentifier identifier: NSCopying?, at p: CGPoint) {
print(identifier)
}
}
Upvotes: 0
Views: 585
Reputation: 747
I completely scrapped my old answer and updated it. I'm sorry I mislead you, but here is my revised answer:
The idea is that you add behaviors to the objects you want animated (in your case, your fallingImageViews
).
So all the code here should actually go into a class that inherits from UIImageView (in my example code you'll see that I'm inheriting from a CardCtrl object, but it might as well be a UIImageView).
The only changes you have to make is your UIDynamicAnimator
's reference view has to be superview
and that all the the reference views for all your animation behaviors are set to [self]
.
Here is some example code from one of my old projects:
@IBDesignable class SlidingCard: CardCtrl, UICollisionBehaviorDelegate
{
...
//MARK: - Private Properties
private var gripHeightAnch: NSLayoutConstraint = NSLayoutConstraint()
private var animator: UIDynamicAnimator!
private var dynamicItem: UIDynamicItemBehavior!
private var collisionBnds: UICollisionBehavior!
private var snap: UISnapBehavior!
private var botBndryPt: CGFloat!
private var gravity: UIGravityBehavior!
private var pan: UIPanGestureRecognizer!
...
//MARK: - Delegate Methods
func collisionBehavior(_ behavior: UICollisionBehavior, beganContactFor item: UIDynamicItem,
withBoundaryIdentifier identifier: NSCopying?, at p: CGPoint)
{
guard let identifier = identifier else {return}
if String(describing: identifier) == "bot"
{
sendActions(for: .touchDragOutside)
}
else
{
sendActions(for: .touchDragInside)
}
}
...
//MARK: - Private Setup Methods
private func defineSlideBehavior()
{
if animator == nil
{
animator = UIDynamicAnimator(referenceView: superview!)
}
animator!.removeAllBehaviors()
//Check to see if behaviors are already installed because .removeAllBehaviors() doesn't
//always work
var addItem = true
var addBounds = true
var addGravity = true
for blarHar in animator!.behaviors
{
if blarHar.isKind(of: UIDynamicItem.self)
{
addItem = false
}
if blarHar.isKind(of: UICollisionBehavior.self)
{
addBounds = false
}
if blarHar.isKind(of: UIGravityBehavior.self)
{
addGravity = false
}
}
//Make it so the card doesn't wobble
if dynamicItem == nil && addItem
{
dynamicItem = UIDynamicItemBehavior(items: [self])
dynamicItem.allowsRotation = false
dynamicItem.elasticity = 0
}
animator!.addBehavior(dynamicItem)
//Add two boundaries for the drawer to collide with
if collisionBnds == nil && addBounds
{
collisionBnds = UICollisionBehavior(items: [self])
collisionBnds.collisionDelegate = self
}
botBndryPt = frame.maxY * 2 + 1.5
collisionBnds.removeAllBoundaries()
collisionBnds.addBoundary(withIdentifier: "top" as NSCopying,
from: CGPoint(x: frame.minX, y: frame.minY - 1.5),
to: CGPoint(x: frame.maxX, y: frame.minY - 1.5))
collisionBnds.addBoundary(withIdentifier: "bot" as NSCopying,
from: CGPoint(x: frame.minX, y: botBndryPt),
to: CGPoint(x: frame.maxX, y: botBndryPt))
animator!.addBehavior(collisionBnds)
//Define the initial gravity that affects the drawer
if addGravity
{
gravity = UIGravityBehavior(items: [self])
gravity.gravityDirection = CGVector(dx: 0, dy: -gravityStrength)
animator!.addBehavior(gravity)
}
}
}
Upvotes: 0