Swift: panel animado UIDynamic de abajo hacia arriba

Quiero crear una vista personalizada simple que se deslice desde la parte inferior con UIDynamicAnimator.

Cuando la aplicación se carga, compensa la vista desde la pantalla usando:

panelWidth = originView!.frame.size.width panelHeight = originView!.frame.size.height/2 screenHeight = originView!.frame.size.height // Set the frame for the container of this view based on the parent container.frame = CGRectMake(0, screenHeight, panelWidth, panelHeight) 

Para visualizar esto, espero que la vista aparezca como:

 |-----| | | | A | <--- Main View | | |-----| |-----| | B | <--- Second View (offset by screen height so it draws directly under (0,height)) |-----| 

He configurado reconocedores de gestos para detectar cuando deslizo hacia arriba y hacia abajo (hasta mostrar, hacia abajo para descartar), sin embargo, en este momento, la vista rebota en la pantalla y nunca puedo recuperarla.

Con mi animador, uso el siguiente código

 animator.removeAllBehaviors() isOpen = open let gravityY:CGFloat = (open) ? -0.5 : 0.5 let gravityX:CGFloat = 0 let magnitude:CGFloat = (open) ? -20 : 20 let boundaryY:CGFloat = (open) ? -panelHeight : panelHeight let boundaryX:CGFloat = (open) ? 0 : 0 

Antes de mostrar el rest del código, creo que debería discutir mis constantes. Las matemáticas vectoriales no son mi punto fuerte, así que esta es probablemente la única razón por la que todo esto va mal. Puse los valores para que sean negativos cuando open es cierto porque quiero volver a animar la vista en la pantalla, lo que significa animarla hacia arriba, por lo tanto, supongo que necesito gravedad negativa.

Puse límite Y para que sea la altura del panel, ya que quiero animarlo en la pantalla solo a la altura de la window, actualmente vuela desde la parte superior (cuando depuré la altura de la pantalla = 667 y panelHeight = 333.5, así que no lo hago) No entiendo por qué excede esa marca)

 // animator behaviours - here I just create animaters on the panels container let gravityBehaviour:UIGravityBehavior = UIGravityBehavior(items: [container]) let collisionBehaviour:UICollisionBehavior = UICollisionBehavior(items: [container]) let pushBehaviour:UIPushBehavior = UIPushBehavior(items: [container], mode: UIPushBehaviorMode.Instantaneous) let panelBehaviour:UIDynamicItemBehavior = UIDynamicItemBehavior(items:[container]) // Gravity behaviour - I don't want it to move in X direction, only Y gravityBehaviour.gravityDirection = CGVectorMake(gravityX, gravityY) // collision detection - I think this is the major problem, how does this work... collisionBehaviour.addBoundaryWithIdentifier("basePanelBoundary", fromPoint: CGPointMake(boundaryX, 0), toPoint: CGPointMake(boundaryX, boundaryY)) // push behaviours pushBehaviour.magnitude = magnitude // panel behaviours panelBehaviour.elasticity = 0.3 // bind behaviours animator.addBehavior(gravityBehaviour) animator.addBehavior(collisionBehaviour) animator.addBehavior(pushBehaviour) animator.addBehavior(panelBehaviour) 

Estoy principalmente preocupado por la detección de colisiones, ya que creo que esto es lo que está causando que la vista gire y salga de la pantalla, ¿cómo puedo solucionar esto?

Después de algunas investigaciones adicionales, me di count de que estaba usando demasiados componentes para lograr la animation que deseaba, también me di count de que mis límites estaban mal definidos y esto es lo que estaba causando que mi panel disparara desde la window.

Para solucionar el problema, primero modifiqué mis límites para que interactuaran con las coorderadas que especificé en la pantalla:

 collisionBehavior.addBoundaryWithIdentifier("upperBoundary", fromPoint: CGPointMake(0, screenHeight - panelHeight), toPoint: CGPointMake(boundaryX, screenHeight - panelHeight)) collisionBehavior.addBoundaryWithIdentifier("lowerBoundary", fromPoint: CGPointMake(0, screenHeight+panelHeight), toPoint: CGPointMake(boundaryX, screenHeight+panelHeight)) 

Luego definí un vector de gravedad cuyo valor fue influenciado en function del valor del toggle boolean open :

 let gravityY:CGFloat = (open) ? -1.5 : 1.5 gravityBehavior.gravityDirection = CGVectorMake(0, gravityY) 

Finalmente até los comportamientos al animador y la animation funcionó como se esperaba.

En resumen, si usted es nuevo en UIDynamics, le aconsejo que pase algún time en papel antes de sumergirse y ensuciarse las manos con el código, una vez que descompuse este problema, fue mucho más fácil que mi primer bash.

Código de trabajo

 func showBasePanel(open:Bool) { animator.removeAllBehaviors() isOpen = open // Define constants to be plugged into animator let gravityY:CGFloat = (open) ? -1.5 : 1.5 let boundaryY:CGFloat = panelHeight let boundaryX:CGFloat = panelWidth // animator behaviours let gravityBehavior:UIGravityBehavior = UIGravityBehavior(items: [container]) let collisionBehavior:UICollisionBehavior = UICollisionBehavior(items:[container]) let panelBehavior:UIDynamicItemBehavior = UIDynamicItemBehavior(items:[container]) // Set the behvaiours panelBehavior.allowsRotation = false panelBehavior.elasticity = 0 // Set collision behaviours collisionBehavior.addBoundaryWithIdentifier("upperBoundary", fromPoint: CGPointMake(0, screenHeight - panelHeight), toPoint: CGPointMake(boundaryX, screenHeight - panelHeight)) collisionBehavior.addBoundaryWithIdentifier("lowerBoundary", fromPoint: CGPointMake(0, screenHeight+panelHeight), toPoint: CGPointMake(boundaryX, screenHeight+panelHeight)) gravityBehavior.gravityDirection = CGVectorMake(0, gravityY) // set the animator behvaiours animator.addBehavior(gravityBehavior) animator.addBehavior(panelBehavior) animator.addBehavior(collisionBehavior) }