2015-01-15 14 views
15

Come parte dell'implementazione di un UICollisionBehaviour, ho impostato i limiti per il bordo dello schermo. Ho quindi aggiunto alcune visualizzazioni e infine allegato UIPanGestureRecognizer a una di esse.UICollisionBehavior - viste passano attraverso i limiti

Ora posso spingere le viste più piccole con la mia vista trascinabile.

Hammer-time!

Problema: Se io angolo una vista più piccolo e continuare a spingere contro il bordo dello schermo, finirà per scivolare oltre il confine e ottenere intrappolati sul lato opposto. La mia "vista del martello" che uso per colpire e spingere le altre viste in giro verrà catturata anche nei limiti. Cioè è bloccato/non trascinabile contro il lato dello schermo.

Ho fatto un esempio molto piccolo per vedere se potevo riprodurlo quando avevo pochissime viste e nessun comportamento in conflitto, le viste continuano a superare i limiti. O l'UIDynamics non può gestire molto o (più probabilmente) in qualche modo lo sto configurando in modo sbagliato.

Il piccolo esempio che segue ha lo strano comportamento:

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

}

Grazie per qualsiasi aiuto dato.

+2

Aggiungi un tag Swift per aiutare la vostra domanda di essere visto. – iOSAaronDavid

+2

Ho anche visto accadere questo. Sembra che quando una vista è spinta attraverso un confine, si formi quasi un buco attraverso il quale altri punti di vista possono passare. Curioso di sentire qualsiasi risposta. – Warpling

risposta

4

Buone notizie: non stai facendo niente di male. Cattive notizie: questo è un comportamento previsto. Il tuo martello spinge la visuale contro i limiti di riferimento fino a quando non si rompe definitivamente perché la fisica della tua modella dice che è ciò che dovrebbe fare. Il limite di riferimento non è un limite che non può essere attraversato, ma definisce solo un'area in cui le regole fisiche si applicano in modo coerente.

questo non è davvero documentato, ma la pagina per UICollisionBehavior afferma:

Quando si imposta la posizione iniziale di un elemento dinamico, è necessario assicurarsi che suoi limiti non si intersecano alcun confine di collisione. Il comportamento di animazione per un articolo fuori posto non è definito.

Questo è solo parzialmente vero, nel tuo caso (come nel mio) se un elemento esce fuori dal limite dopo l'inizializzazione, anche il suo comportamento è indefinito.

Ho provato a sistemare una serie di sfere sul lato destro di una vista. C'è un punto di ancoraggio sotto la palla più a destra. La vista gialla è la vista di riferimento e tutto parte bene ... this works

Ma, come ho aggiunto più palle a indicare che non potevano più adattarsi, avrebbero iniziato a saltar fuori. Infatti, quello in alto a destra dell'immagine è saltato fuori dal centro in basso e ruotato attorno alla vista di riferimento in senso antiorario per essere vicino al punto di ancoraggio. this is broken

UPDATE: Per una soluzione è possibile impostare il collisionDelegate dei tuoi collisionBehaviors e catturare l'inizio e la fine delle collisioni e quindi spostare la visualizzazione nuovamente dentro il confine e lontano dal tuo martello per far sembrare sono fuggiti.

Come hai capito translatesReferenceBoundsIntoBoundary equivale al set di chiamate addBoundaryWithIdentifier.

Usa:

collisionBehaviour!.translatesReferenceBoundsIntoBoundary = true 

stessa:

//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

Grazie per gli approfondimenti, rivisiterò la mia piccola demo per vedere se riesco a forzare di nuovo le palle all'interno del confine, senza che sia strano. – RickiG

Problemi correlati