ios - UICollisionBehavior-las vistas pasan a través de los límites
swift ios8.1 (1)
Como parte de la implementación de un UICollisionBehaviour, establezco límites para el borde de la pantalla. Luego agregué algunas vistas y finalmente adjunté un UIPanGestureRecognizer a una de ellas.
Ahora puedo desplazar las vistas más pequeñas con mi vista que se puede arrastrar.
Problema: si acorrao una vista más pequeña y la empujo contra el borde de la pantalla, eventualmente se deslizará más allá del límite y quedará atrapada en el otro lado. Mi "vista de martillo" que uso para golpear y empujar a las otras vistas alrededor también quedará atrapada en los límites. Es decir, se atasca / no se puede arrastrar contra el lado de la pantalla.
Hice un ejemplo muy pequeño para ver si podía reproducirlo cuando tenía muy pocas vistas y no tenía comportamientos conflictivos, las vistas aún atraviesan los límites. O bien UIDynamics no puede manejar mucho, o (lo más probable) es que estoy configurando mal de alguna manera.
El pequeño ejemplo a continuación tiene el comportamiento extraño:
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.
}
}
Gracias por cualquier ayuda prestada.
Buenas noticias: no estás haciendo nada malo. Malas noticias: este es el comportamiento esperado. Su martillo está empujando la vista contra los límites de referencia hasta que finalmente se abre paso porque la física de su modelo dice que eso es lo que debe hacer. El límite de referencia no es un límite que no se pueda cruzar, solo define un área donde las reglas de física se aplican de manera coherente.
Esto no está realmente documentado, pero la página de UICollisionBehavior dice:
Al configurar la posición inicial para un elemento dinámico, debe asegurarse de que sus límites no se intersecan con ningún límite de colisión. El comportamiento de la animación para un elemento fuera de lugar es indefinido.
Esto es solo parcialmente cierto, en su caso (como en el mío) si un artículo se sale del límite después de la inicialización, su comportamiento también está indefinido.
Intenté colocar un juego de bolas en el lado derecho de una vista. Hay un punto de anclaje debajo de la bola más a la derecha. La vista amarilla es la vista de referencia y todo comienza bien ...
Pero, a medida que agregué más bolas a los puntos que ya no podían encajar, comenzarían a saltar. De hecho, el que está en la parte superior derecha de la imagen salió del centro de la parte inferior y giró alrededor de la vista de referencia en sentido contrario a las agujas del reloj para estar cerca del punto de anclaje.
ACTUALIZACIÓN: para una solución, puede establecer el ColisionDelegate de sus comportamientos de colisión y capturar el inicio y el final de las colisiones y luego mover su vista de nuevo hacia el límite y alejarse de su martillo para que parezca que se escaparon.
Como ha descubierto, tradlatesReferenceBoundsIntoBoundary es equivalente al conjunto de llamadas addBoundaryWithIdentifier.
Utilizar:
collisionBehaviour!.translatesReferenceBoundsIntoBoundary = true
igual que:
//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))