Методы UICollisionBehaviorDelegate не вызваны

Я работал над приложением и реализовал обнаружение столкновений, используя UIKitDynamics.

Обнаружение столкновения работает. Но почему-то методы UICollisionBehaviorDelegate не вызываются. Предупреждения или ошибки не отображаются.

Я создал пример проекта, чтобы продемонстрировать проблему:

  import UIKit

  class ViewController: UIViewController {
    private var dynamicAnimator: UIDynamicAnimator?

    override func viewDidLoad() {
      super.viewDidLoad()
      // Do any additional setup after loading the view, typically from a nib.
    }

    override func viewDidAppear(_ animated: Bool) {
      super.viewDidAppear(animated)

      self.initPhysics()
    }

    fileprivate var initalized = false
    fileprivate func initPhysics() {
      if initalized {
        return
      }
      initalized = true

      let physicsView = UIView(frame: view.bounds.insetBy(dx: 40, dy: 40))
      physicsView.backgroundColor = UIColor.black

      self.dynamicAnimator = UIDynamicAnimator(referenceView: physicsView)

      physicsView.isUserInteractionEnabled = false
      view.addSubview(physicsView)

      //Create ball
      let frame = CGRect(x: 0, y: 0, width: 40, height: 40)

      let rect = UIView(frame: frame)
      rect.backgroundColor = UIColor.red
      physicsView.addSubview(rect)

      let behavior = UIDynamicItemBehavior(items: [rect])
      behavior.elasticity = 1.0
      behavior.resistance = 0.0
      behavior.friction = 0.0
      behavior.allowsRotation = false
      self.dynamicAnimator?.addBehavior(behavior)

      //collision behavior setup
      let collisionBehavior = UICollisionBehavior(items: [rect])
      collisionBehavior.collisionDelegate = self
      collisionBehavior.setTranslatesReferenceBoundsIntoBoundary(with: .zero)
      collisionBehavior.collisionMode = .everything
      self.dynamicAnimator?.addBehavior(collisionBehavior)

      //Push ball
      let pushBehavior = UIPushBehavior(items: [rect], mode: UIPushBehaviorMode.instantaneous)
      pushBehavior.active = true
      pushBehavior.pushDirection = CGVector(dx: 0.5, dy: 0.5)
      self.dynamicAnimator?.addBehavior(pushBehavior)
    }
  }

  extension ViewController: UICollisionBehaviorDelegate {
    // DELEGATE METHODS NOT CALLED
    func collisionBehavior(_ behavior: UICollisionBehavior,
                           beganContactFor item: UIDynamicItem,
                           withBoundaryIdentifier identifier: NSCopying?,
                           at p: CGPoint) {
      print("began contact boundary")
    }

    func collisionBehavior(_ behavior: UICollisionBehavior,
                           endedContactFor item: UIDynamicItem,
                           withBoundaryIdentifier identifier: NSCopying?) {
      print("contact boundary ended")
    }

    func collisionBehavior(_ behavior: UICollisionBehavior,
                           endedContactFor item1: UIDynamicItem,
                           with item2: UIDynamicItem) {

      print("contact item ended")
    }

    func collisionBehavior(_ behavior: UICollisionBehavior,
                           beganContactFor item1: UIDynamicItem,
                           with item2: UIDynamicItem,
                           at p: CGPoint) {
      print("began contact item")
    }
  }

Базовый SDK: iOS 11.2, Xcode Version 9.2 (9C40b)

Спасибо за помощь!

1 ответ

Решение

Это не то, как это работает (к сожалению).. У вас есть только один элемент в вашем поведении столкновения, и вы просите его обнаружить столкновение с чем??? Если вы добавили второй элемент, вы увидите, что делегат вызван..

Реальный вопрос почему? Ну, столкновение обнаруживает, пересекается ли кадр одного элемента с кадром другого.. Если он сделал то, что вы просите (rect это ребенок physicsView), тогда он ВСЕГДА будет сталкиваться (это не то, что вы хотите)..

Так как ваш physicsView не является частью поведения при столкновении, вы ничего не получаете.. Вы сказали ему ограничить элемент в его пределах (setTranslatesReferenceBoundsIntoBoundary работает над элементами, добавленными к самому поведению), но не для обнаружения столкновения с границами. Например, если элемент находился вне physicsView, он не сможет войти. Если он внутри, он не может выйти. Но это не будет считаться столкновением за слово (иначе это всегда столкновение).

Для того, чтобы обнаружить столкновение между вашим rect и ваш physicsViewнужно дать physicsView некоторые физические свойства.. Сейчас это просто обычный UIView (справочный вид)..

Другой способ обойти физические свойства - добавить для него границу:

collisionBehavior.addBoundary(withIdentifier: "PhysicsViewBoundary" as NSString, for: UIBezierPath(rect: physicsView.bounds))

Теперь он позвонит:

func collisionBehavior(_ behavior: UICollisionBehavior,
                       beganContactFor item: UIDynamicItem,
                       withBoundaryIdentifier identifier: NSCopying?,
                       at p: CGPoint) {
    print("began contact boundary")
}

func collisionBehavior(_ behavior: UICollisionBehavior,
                       endedContactFor item: UIDynamicItem,
                       withBoundaryIdentifier identifier: NSCopying?) {
    print("contact boundary ended")
}
Другие вопросы по тегам