简体   繁体   English

Swift:UIDynamic动画面板从下到上

[英]Swift: UIDynamic animate panel from bottom to top

I want to build a simple custom view which slides up from the bottom with UIDynamicAnimator. 我想构建一个简单的自定义视图,使用UIDynamicAnimator从底部向上滑动。

When the app loads I offset the view from the screen using: 当应用程序加载时,我使用以下方法从屏幕偏移视图:

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)

To envision this, I expect the view to appear as: 为了设想这一点,我希望视图显示为:

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

I have set up gesture recognisers to detect when I swipe up and down (up to show, down to dismiss), however right now the view bounces off the screen and I can never seem to get it back. 我已经设置了手势识别器来检测我何时向上和向下滑动(向上显示,向下扫描),但是现在视图从屏幕反弹并且我似乎永远无法将其取回。

With my animator, I use the following code 使用我的动画师,我使用以下代码

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

Before showing the rest of the code, I think I should discuss my constants. 在显示其余代码之前,我想我应该讨论我的常量。 Vector math is not my strong point so this is probably the sole reason all of this is going wrong. 矢量数学不是我的强项,所以这可能是所有这一切都出错的唯一原因。 I set the values to be negative on when open is true because I want to animate the view back onto the screen which means animating it upward, therefore I assume I need negative gravity. open为true时,我将值设置为负值,因为我想将视图设置回屏幕动画,这意味着向上动画,因此我假设我需要负重力。

I set boundaryY to be the height of the panel as I want to animate it up onto the screen only to the height of the window, currently it flies off the top (when I debugged screen height = 667 and panelHeight = 333.5 so I don't understand why it exceeds that mark) 我将boundaryY设置为面板的高度,因为我想将它设置为屏幕上的动画,仅限于窗口的高度,目前它从顶部飞过(当我调试屏幕高度= 667并且panelHeight = 333.5所以我不喜欢明白为什么它超过那个标记)

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

I'm mainly concerned with the collision detection as I believe this is what is causing the view to rotate and fling off the screen, how can I fix this? 我主要关注碰撞检测,因为我认为这是导致视图旋转并从屏幕上掉落的原因,我该如何解决这个问题呢?

After some further research I realised I was using far too many components to achieve the animation I desired, I also realised my boundaries were poorly defined and this is what was causing my panel to shoot off the window. 经过一些进一步的研究,我意识到我使用了太多的组件来实现我想要的动画,我也意识到我的边界定义不明确,这就是导致我的面板从窗户射出的原因。

To fix the issue I first amended my boundaries so that they would co-inside with the coordinates I specified on the screen: 为了解决这个问题,我首先修改了边界,以便它们与我在屏幕上指定的坐标共同内部:

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

I then defined a gravity vector thats value was influenced based on the value of the open boolean toggle: 然后我定义了一个重力向量,该值基于open boolean toggle的值受到影响:

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

Finally I bound the behaviours to the animator and the animation worked as expected. 最后,我将行为绑定到动画师,动画按预期工作。

In summary, if you are new to UIDynamics, I'd advise spending some time on paper before diving in and getting your hands dirty with the code, once I decomposed this problem it was far easier than my first attempt. 总而言之,如果你是UIDynamics的新手,我建议你在潜水之前花一些时间在纸上,然后把手弄脏代码,一旦我解决了这个问题,它就比我的第一次尝试容易得多。

Working Code 工作守则

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM