简体   繁体   English

UICollisionBehavior - 视图通过边界

[英]UICollisionBehavior - views pass through boundaries

As part of implementing a UICollisionBehaviour I set up boundaries for the screen edge. 作为实现UICollisionBehaviour的一部分,我为屏幕边缘设置了边界。 I then added some views and finally attached a UIPanGestureRecognizer to one of them. 然后我添加了一些视图,最后将一个UIPanGestureRecognizer附加到其中一个。

Now I can push around the smaller views with my draggable view. 现在我可以使用我的可拖动视图来推动较小的视图。

锤时间!

Problem: If I corner a smaller view and keep pushing it against the screen edge, it will eventually slip past the boundary and get trapped on the other side. 问题:如果我将较小的视角转向并将其推向屏幕边缘,它最终将滑过边界并被困在另一侧。 My "hammer view" that I use to hit and push the other views around with will also get caught in the boundaries. 我用来击打和推动其他视图的“锤子视图”也会陷入界限。 Ie it get's stuck/un-draggable against the side of the screen. 即它在屏幕的一侧被卡住/不可拖动。

I did a very small example to see if I could reproduce it when I had very few views and no conflicting behaviours, views still go through the boundaries. 我做了一个非常小的例子,看看当我的视图很少而且没有相互冲突的行为时我是否可以重现它,视图仍然可以通过边界。 Either UIDynamics can't handle very much, or (more likely) I am somehow configuring it wrong. 无论是UIDynamics都无法处理,或者(更有可能)我以某种方式配置错误。

The small example below has the weird behaviour: 下面的小例子有奇怪的行为:

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

} }

Thanks for any help given. 谢谢你给予的任何帮助。

Good news: you aren't doing anything wrong. 好消息:你没有做错任何事。 Bad news: this is expected behavior. 坏消息:这是预期的行为。 Your hammer is pushing the view against the reference boundaries until it finally breaks through because the physics of your model says that's what it should do. 你的锤子正在将视图推向参考边界,直到它最终突破,因为模型的物理特性表明它应该做什么。 The reference boundary is not a boundary that can't be crossed, it only defines an area where your physics rules apply consistently. 参考边界不是不能越过的边界,它只定义物理规则一致应用的区域。

This isn't really documented, but the page for UICollisionBehavior states: 这没有真正记录,但UICollisionBehavior的页面指出:

When setting the initial position for a dynamic item, you must ensure that its bounds do not intersect any collision boundaries. 设置动态项的初始位置时,必须确保其边界不与任何碰撞边界相交。 The animation behavior for such a misplaced item is undefined. 这种放错位置的项目的动画行为是未定义的。

This is only partially true, in your case (as with mine) if an item goes outside the boundary after initialization, it's behavior is also undefined. 这只是部分正确,在你的情况下(和我一样)如果一个项目在初始化之后超出边界,它的行为也是未定义的。

I tried to arrange a set of balls on the right side of a view. 我试图在视图的右侧安排一组球。 There is an anchor point under the rightmost ball. 最右边的球下面有一个锚点。 The yellow view is the reference view and everything starts off fine... 黄色视图是参考视图,一切都很好...... 这很有效

But, as I added more balls to they point they could no longer fit, they would start to pop out. 但是,当我向他们添加更多的球时他们指出他们已经不再合适了,他们就会开始蹦出来。 In fact, the one on the top right of the image popped out of the bottom center and rolled around the reference view counter clockwise to be near the anchor point. 事实上,图像右上角的那个从底部中心弹出,并逆时针绕参考视图滚动到靠近锚点。 这已破了

UPDATE: For a solution you can set the collisionDelegate of your collisionBehaviors and capture the start and ends of the collisions and then move your view back into the boundary and away from your hammer to make it look like they escaped. 更新:对于解决方案,您可以设置collisionBehaviors的collisionDelegate并捕获碰撞的开始和结束,然后将视图移回边界并远离锤子,使其看起来像是逃脱的。

As you have figured out translatesReferenceBoundsIntoBoundary is equivalent to the set of addBoundaryWithIdentifier calls. 正如您所知,translatesReferenceBoundsIntoBoundary相当于addBoundaryWithIdentifier调用的集合。

Use: 使用:

collisionBehaviour!.translatesReferenceBoundsIntoBoundary = true 

same as: 与...一样:

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

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

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