Swift - 不被调用的UICollisionBehavior委托方法

问题描述:

我正在做一个简单的动画,它需要我处理边界的碰撞。Swift - 不被调用的UICollisionBehavior委托方法

我有一个类,viewcontroller,我扩展为一个UICollisionBehaviorDelegate,所以我可以识别并处理视图冲突。

由于某些原因,当碰撞发生时,我的委托方法从不触发。

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) 
    } 
} 

我完全废弃了旧的答案并更新了它。对不起,我误导了你,但这里是我修改后的答案:

这个想法是你想要动画的对象添加行为(在你的情况下,你的fallingImageViews)。

所以这里的所有代码实际上应该进入从UIImageView继承的类(在我的示例代码中,您将看到我从CardCtrl对象继承,但它可能也是UIImageView)。

您必须做出的唯一更改是您的UIDynamicAnimator的参考视图必须是superview,并且所有动画行为的所有参考视图都设置为[self]

这里是我的老项目之一一些示例代码:

@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) 
     } 
    } 
} 
+0

眼下,边界正在正确应用 - 即,在元素fallingimageViews与参考范围相冲突。 我试图解决的问题是,当这个碰撞发生时,'collisionBehaviorBeganContactFor方法'不会被触发。 – Beezebrown

+0

您的委托不会触发,因为您的视图控制器符合UICollisionBehaviorDelegate,而不是您的fallingImageViews。 如果您将collisionDelegate分配给self,那么您的视图控制器将成为碰撞的观察者,但在您的情况下,您的视图控制器没有碰撞边界,那么应该如何检测碰撞? (对不起,在我完全输入我的答案之前,我不小心输入了过早) –

+0

你试过我的建议吗? (将'items:fallingImageViews'改为'items:[self.view]') –

尝试改变线let downAnimator = initializeAnimators()viewDidLoad()downAnimator = initializeAnimators()

+0

对不起,这是发布的代码示例中的一个错字,而不是我自己的。 – Beezebrown