UICollisionBehavior - 视图穿过边界

18

为了实现UICollisionBehavior,我设置了屏幕边缘的边界。然后添加了一些视图,并最终将UIPanGestureRecognizer附加到其中一个视图。

现在我可以使用可拖动视图来推动小视图。

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
1个回答

7
好消息是:你没有做错任何事情。坏消息是:这是预期的行为。你的锤子将视图推到参考边界,直到最终突破,因为模型的物理规则要求如此。参考边界不是不能越过的边界,它只定义了一个区域,在这个区域里你的物理规则始终适用。
虽然这并没有真正被文档化,但 UICollisionBehavior 的页面指出:
当为动态项设置初始位置时,必须确保其边界不与任何碰撞边界相交。对于这样一个放置不当的项的动画行为是未定义的。
这只是部分正确的,在你的情况下(就像我的情况一样),如果一个项在初始化后超出了边界,它的行为也是未定义的。
我试图在一个视图的右侧排列一组球。右侧最后一个球下面有一个锚点。黄色视图是参考视图,一切都开始得很好...
但是,随着我添加更多的球,它们无法再适应,它们会开始弹出。实际上,图片右上角的那个球从底部中心弹出,并沿着参考视图逆时针滚动到靠近锚点的位置。
更新: 解决方法是设置碰撞行为的碰撞委托(collisionDelegate),捕获碰撞的开始和结束,然后将你的视图移回边界并远离你的锤子,使它看起来像是它们逃脱了。
正如您已经发现的那样,translatesReferenceBoundsIntoBoundary 等价于 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))

谢谢您的见解,我会重新审视我的小演示,看看是否可以再次将球强制放在边界内,而不让它看起来太奇怪。 - RickiG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接