【问题标题】:In Swift’s UIKit Dynamics, how can I define a circle boundary to contain a UIView?在 Swift 的 UIKit Dynamics 中,如何定义一个圆的边界来包含一个 UIView?
【发布时间】:2018-04-06 23:39:47
【问题描述】:

我研究了很多,但我能在任何地方找到的唯一示例是为了定义 UIView 的边界,以便它们在对象的外部相互碰撞/反弹。

示例:一个球撞到另一个球,它们相互弹开。

但我想做的是创建一个圆形视图来包含其他 UIView,这样包含边界是一个圆形,而不是默认的正方形。有没有办法做到这一点?

【问题讨论】:

    标签: swift animation collision-detection uikit-dynamics


    【解决方案1】:

    是的,这完全可能。实现圆内碰撞的关键是

    1. 将碰撞行为的边界设置为圆形路径(自定义UIBezierPath)和
    2. 将动画师的referenceView 设置为圆形视图。

    输出:

    故事板设置:

    下面是上述 Storyboard 的视图控制器的代码。魔法发生在simulateGravityAndCollision 方法中:

    Full Xcode project

    class ViewController: UIViewController {
    
        @IBOutlet weak var redCircle: UIView!
        @IBOutlet weak var whiteSquare: UIView!
    
        var animator:UIDynamicAnimator!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.redCircle.setCornerRadius(self.redCircle.bounds.width / 2)
        }
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5) { [unowned self] in
                self.simulateGravityAndCollision()
            }
        }
    
        //IMPORTANT
        func simulateGravityAndCollision() {
    
            //The dynamic animation happens only within the reference view, i.e., our red circle view
            animator = UIDynamicAnimator.init(referenceView: self.redCircle)
    
            //Only the inside white square will be affected by gravity
            let gravityBehaviour = UIGravityBehavior.init(items: [self.whiteSquare])
    
            //We also apply collision only to the white square
            let collisionBehaviour = UICollisionBehavior.init(items:[self.whiteSquare])
    
            //This is where we create the circle boundary from the redCircle view's bounds
            collisionBehaviour.addBoundary(withIdentifier: "CircleBoundary" as NSCopying, for: UIBezierPath.init(ovalIn: self.redCircle.bounds))
    
            animator.addBehavior(gravityBehaviour)
            animator.addBehavior(collisionBehaviour)
        }
    
    }
    
    extension UIView {
    
        open override func awakeFromNib() {
            super.awakeFromNib()
            self.layer.allowsEdgeAntialiasing = true
        }
    
        func setCornerRadius(_ amount:CGFloat) {
            self.layer.cornerRadius = amount
            self.layer.masksToBounds = true
            self.clipsToBounds = true
        }
    }
    

    【讨论】:

    • 哇!做得好!我最终创建了 3 条单独的边界线(在圆的底部有一条,每边有 1 条向上倾斜)。它绝不优雅,但它与我所追求的外观完全相同。我不明白你的 viewDidAppear() 里面有什么......新手......但你的输出正是我试图实现的大约 4 天大声笑。干得好!谢谢!
    • @Justin 没问题。很高兴您的问题得到解决!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 2011-10-22
    • 2016-06-06
    • 1970-01-01
    • 2020-11-04
    • 1970-01-01
    相关资源
    最近更新 更多