2015-01-15 4 views
15

В рамках реализации UICollisionBehaviour я устанавливаю границы для края экрана. Затем я добавил некоторые взгляды и, наконец, прикрепил к одному из них UIPanGestureRecognizer.UICollisionBehavior - виды проходят через границы

Теперь я могу обойти меньшие виды с помощью своего перетаскиваемого вида.

Hammer-time!

Проблема: Если я угол меньший вид и толкать его к краю экрана, то в конечном счете проскользнуть мимо границы и попасть в ловушку с другой стороны. Мой «вид молотка», который я использую для того, чтобы ударить и подтолкнуть другие виды вокруг, также попадет в границы. То есть он застрял/не перетаскивался в сторону экрана.

Я сделал очень маленький пример, чтобы увидеть, могу ли я воспроизвести его, когда у меня было очень мало просмотров и не было противоречивого поведения, а виды все еще проходят через границы. Либо UIDynamics не может справиться очень много, либо (более вероятно), я каким-то образом неправильно настроил ее.

Небольшой пример ниже имеет странное поведение:

class ViewController: UIViewController { 

var animator: UIDynamicAnimator? 
var collisionBehaviour: UICollisionBehavior? 
var panBehaviour: UIAttachmentBehavior? 

override func viewDidLoad() { 
    super.viewDidLoad() 
} 

override func viewWillAppear(animated: Bool) { 
    super.viewWillAppear(animated) 
    setup() 
} 

func setup() { 
    //setup collisionBehaviour and animator 
    collisionBehaviour = UICollisionBehavior() 
    collisionBehaviour!.collisionMode = UICollisionBehaviorMode.allZeros 
    animator = UIDynamicAnimator(referenceView: view) 

    //add boundaries 
    collisionBehaviour!.addBoundaryWithIdentifier("verticalMin", fromPoint: CGPointMake(0, 0), toPoint: CGPointMake(0, CGRectGetHeight(view.frame))) 
    collisionBehaviour!.addBoundaryWithIdentifier("verticalMax", fromPoint: CGPointMake(CGRectGetMaxX(view.frame), 0), toPoint: CGPointMake(CGRectGetMaxX(view.frame), CGRectGetHeight(view.frame))) 
    collisionBehaviour!.addBoundaryWithIdentifier("horizontalMin", fromPoint: CGPointMake(0, CGRectGetMaxY(view.frame)), toPoint: CGPointMake(CGRectGetMaxX(view.frame), CGRectGetMaxY(view.frame))) 
    collisionBehaviour!.addBoundaryWithIdentifier("horizontalMax", fromPoint: CGPointMake(0, 0), toPoint: CGPointMake(CGRectGetMaxX(view.frame), 0)) 

    //  collisionBehaviour!.translatesReferenceBoundsIntoBoundary = true // same effect as the above boundaries 
    //setup up some round views to push around 
    for i in 0..<5 { 
     let ball = UIView(frame: CGRectMake(0, 30, 50, 50)) 
     ball.center = view.center 
     ball.backgroundColor = UIColor.greenColor() 
     ball.layer.cornerRadius = CGRectGetWidth(ball.frame) * 0.5 
     view.addSubview(ball) 
     collisionBehaviour!.addItem(ball) 
    } 

    //setup a hammer view which can be dragged and used to squeze the ball views of the screen 
    let hammer = UIView(frame: CGRectMake(0, 0, 100, 100)) 
    hammer.backgroundColor = UIColor.redColor() 
    view.addSubview(hammer) 
    collisionBehaviour!.addItem(hammer) 

    let noRotationBehaviour = UIDynamicItemBehavior(items: [hammer]) 
    noRotationBehaviour.allowsRotation = false 
    animator!.addBehavior(noRotationBehaviour) 

    let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: Selector("handlePan:")) 
    hammer.addGestureRecognizer(panGestureRecognizer) 

    //"start" the collision detection 
    animator!.addBehavior(collisionBehaviour!) 
} 

//Move the hammer around 
func handlePan(recognizer: UIPanGestureRecognizer) { 
    if let view = recognizer.view { 
     let location = recognizer.locationInView(self.view) 
     switch recognizer.state { 
     case .Began: 
      panBehaviour = UIAttachmentBehavior(item: view, attachedToAnchor: location) 
      animator!.addBehavior(panBehaviour!) 
      println("begin") 
     case .Changed: 
      panBehaviour!.anchorPoint = location 
      println("change \(location)") 
     case .Ended: 
      println("ended") 
      animator!.removeBehavior(panBehaviour!) 
     default: 
      println("done") 
     } 
    } 
} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 

}

Спасибо за любую помощь, оказанную.

+2

Добавить Swift тег, чтобы помочь ваш вопрос будет рассматриваться. – iOSAaronDavid

+2

Я также видел, как это происходит. Кажется, что, когда взгляд нажимается через границу, он почти образует отверстие, через которое могут проходить другие виды. Любопытно слышать ответы. – Warpling

ответ

4

Хорошие новости: вы ничего не делаете неправильно. Плохая новость: это ожидаемое поведение. Ваш молот толкает взгляд на контрольные границы, пока он, наконец, не прорвется, потому что физика вашей модели говорит, что это то, что она должна делать. Эталонная граница не является границей, которую нельзя пересечь, она определяет только область, в которой ваши физические правила применяются последовательно.

Это на самом деле не документирован, но страница для UICollisionBehavior гласит:

При установке начального положения для динамического элемента, вы должны обеспечить , что ее границы не пересекаются никаких границ столкновения. Поведение анимации для такого неуместного элемента не определено.

Это лишь частично верно в вашем случае (как и у меня), если элемент выходит за границу после инициализации, это поведение также не определено.

Я попытался устроить набор шаров в правой части окна. Под правым шаром имеется опорная точка. Желтый вид - эталонный вид, и все начинается с прекрасного ... this works

Но, поскольку я добавил больше шаров, они указывают, что они больше не подходят, они начнут выскакивать. В самом деле, один на верхней правой части изображения выскочил из нижнего центра и проката вокруг опорного зрения против часовой стрелки, чтобы быть вблизи точки привязки. this is broken

UPDATE: Для решения вы можете установить collisionDelegate ваших collisionBehaviors и захватить начало и концы столкновений, а затем переместить ваш взгляд назад в границу и от молотка, чтобы сделать его похожим они сбежали.

Как вы поняли, переводыReferenceBoundsIntoBoundary эквивалентны вызовам addBoundaryWithIdentifier.

Использование:

collisionBehaviour!.translatesReferenceBoundsIntoBoundary = true 

же, как:

//add boundaries 
    collisionBehaviour!.addBoundaryWithIdentifier("verticalMin", fromPoint: CGPointMake(0, 0), toPoint: CGPointMake(0, CGRectGetHeight(view.frame))) 
    collisionBehaviour!.addBoundaryWithIdentifier("verticalMax", fromPoint: CGPointMake(CGRectGetMaxX(view.frame), 0), toPoint: CGPointMake(CGRectGetMaxX(view.frame), CGRectGetHeight(view.frame))) 
    collisionBehaviour!.addBoundaryWithIdentifier("horizontalMin", fromPoint: CGPointMake(0, CGRectGetMaxY(view.frame)), toPoint: CGPointMake(CGRectGetMaxX(view.frame), CGRectGetMaxY(view.frame))) 
    collisionBehaviour!.addBoundaryWithIdentifier("horizontalMax", fromPoint: CGPointMake(0, 0), toPoint: CGPointMake(CGRectGetMaxX(view.frame), 0)) 
+0

Благодарим вас за понимание, я снова рассмотрю свою небольшую демонстрацию, чтобы увидеть, могу ли я снова заставить шары внутри границы, не глядя на странные. – RickiG