18

UICollisionBehaviour の実装の一環として、画面の端に境界を設定しました。次に、いくつかのビューを追加し、最終的にそれらの 1 つに UIPanGestureRecognizer をアタッチしました。

これで、ドラッグ可能なビューを使用して小さいビューを移動できます。

ハンマータイム!

問題: 小さいビューを隅に置いて画面の端に押し付け続けると、最終的には境界をすり抜けて反対側に引っかかってしまいます。他のビューを叩いたり押したりするために使用する「ハンマービュー」も、境界に引っ掛かります。つまり、画面の端に引っかかったり、ドラッグできなくなったりします。

ビューが非常に少なく、競合する動作がなく、ビューがまだ境界を通過しているときに再現できるかどうかを確認するために、非常に小さな例を作成しました。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.
}

}

助けてくれてありがとう。

4

1 に答える 1

7

良いニュース: あなたは何も悪いことをしていません。悪いニュース: これは予期された動作です。あなたのハンマーは、モデルの物理学がそうすべきだと言っているので、最終的に突破するまでビューを参照境界に押し付けています。参照境界は、越えることができない境界ではなく、物理法則が一貫して適用される領域を定義するだけです。

これは実際には文書化されていませんが、UICollisionBehavior のページには次のように記載されています。

動的アイテムの初期位置を設定するときは、その境界が衝突境界と交差しないようにする必要があります。このような誤って配置されたアイテムのアニメーションの動作は未定義です。

これは部分的にのみ当てはまります。あなたの場合(私の場合と同様)、アイテムが初期化後に境界の外に出た場合、その動作も未定義です。

ビューの右側にボールのセットを配置しようとしました。一番右のボールの下にアンカーポイントがあります。黄色のビューは参照ビューで、すべてが正常に開始されます... これは動作します

しかし、ボールを追加すると、ボールが収まらなくなり、飛び出し始めました。実際、画像の右上にあるものは、下部中央から飛び出し、参照ビューを反時計回りに回転してアンカーポイントの近くにいます. これは壊れています

更新: 解決策として、collisionBehaviors の 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))
于 2015-07-22T02:36:15.980 に答える