如何将多个 UIDynamicItem 相互附加

Posted

技术标签:

【中文标题】如何将多个 UIDynamicItem 相互附加【英文标题】:How to attach multiple UIDynamicItems to each other 【发布时间】:2019-04-20 09:55:24 【问题描述】:

我正在尝试通过UIDynamicAnimator 在 Apple 的音乐应用中实现相互连接的圈子。我需要将圆圈相互连接并查看中心。我试图通过UIAttachmentBehavior 实现这一点,但似乎它不支持多个附件。结果,圆圈相互重叠:)

let attachment = UIAttachmentBehavior(item: circle, attachedToAnchor: CGPoint(x: view.center.x, y: view.center.y))
attachment.length = 10
animator?.addBehavior(attachment)

let push = UIPushBehavior(items: [circle], mode: .continuous)

collision.addItem(circle)

animator?.addBehavior(push)

我做错了什么?

【问题讨论】:

您想将所有圆圈相互连接,还是要将圆圈作为您的第一张图片? 每个行为都可以有孩子。 @Darshan Patel 作为第一张图片 【参考方案1】:

我不认为苹果音乐流派选择器使用UIAttachmentBehavior,它更接近于用一根杆子或一根绳子连接两个视图。但是,您遇到的问题似乎是所有视图都添加在同一位置,这具有将它们放在彼此之上的效果,并且碰撞行为导致它们基本上粘在一起。要做的一件事是通过调用animator.setValue(true, forKey: "debugEnabled") 打开UIDynamicAnimator 调试。

为了重新创建上述圆圈选择器设计,我会考虑使用UIFieldBehavior.springField()

例如:

class ViewController: UIViewController 

    lazy var animator: UIDynamicAnimator = 
        let animator = UIDynamicAnimator(referenceView: view)
        return animator
    ()
    lazy var collision: UICollisionBehavior = 
        let collision = UICollisionBehavior()
        collision.collisionMode = .items
        return collision
    ()
    lazy var behavior: UIDynamicItemBehavior = 
        let behavior = UIDynamicItemBehavior()
        behavior.allowsRotation = false
        behavior.elasticity = 0.5
        behavior.resistance = 5.0
        behavior.density = 0.01
        return behavior
    ()
    lazy var gravity: UIFieldBehavior = 
        let gravity = UIFieldBehavior.springField()
        gravity.strength = 0.008
        return gravity
    ()
    lazy var panGesture: UIPanGestureRecognizer = 
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.didPan(_:)))
        return panGesture
    ()

    var snaps = [UISnapBehavior]()
    var circles = [CircleView]()

    override func viewDidLoad() 
        super.viewDidLoad()
        view.addGestureRecognizer(panGesture)
        animator.setValue(true, forKey: "debugEnabled")
        addCircles()
        addBehaviors()
    

    override func viewDidLayoutSubviews() 
        super.viewDidLayoutSubviews()
        gravity.position = view.center
        snaps.forEach 
            $0.snapPoint = view.center
        
    

    func addCircles() 
        (1...30).forEach  index in
            let xIndex = index % 2
            let yIndex: Int = index / 3
            let circle = CircleView(frame: CGRect(origin: CGPoint(x: xIndex == 0 ? CGFloat.random(in: (-300.0 ... -100)) : CGFloat.random(in: (500 ... 800)), y: CGFloat(yIndex) * 200.0), size: CGSize(width: 100, height: 100)))
            circle.backgroundColor = .red
            circle.text = "\(index)"
            circle.textAlignment = .center
            view.addSubview(circle)
            gravity.addItem(circle)
            collision.addItem(circle)
            behavior.addItem(circle)
            circles.append(circle)
        
    

    func addBehaviors() 
        animator.addBehavior(collision)
        animator.addBehavior(behavior)
        animator.addBehavior(gravity)
    

    @objc
    private func didPan(_ sender: UIPanGestureRecognizer) 
        let translation = sender.translation(in: sender.view)
        switch sender.state 
        case .began:
            animator.removeAllBehaviors()
            fallthrough
        case .changed:
            circles.forEach  $0.center = CGPoint(x: $0.center.x + translation.x, y: $0.center.y + translation.y)
        case .possible, .cancelled, .failed:
            break
        case .ended:
            circles.forEach  $0.center = CGPoint(x: $0.center.x + translation.x, y: $0.center.y + translation.y)
            addBehaviors()
        @unknown default:
            break
        
        sender.setTranslation(.zero, in: sender.view)
    


final class CircleView: UILabel 

    override var collisionBoundsType: UIDynamicItemCollisionBoundsType 
        return .ellipse
    

    override func layoutSubviews() 
        super.layoutSubviews()
        layer.cornerRadius = bounds.height * 0.5
        layer.masksToBounds = true
    

如需更多信息,我会观看 WWDC 2015 上的 What's New in UIKit Dynamics and Visual Effects

【讨论】:

非常感谢。你已经实现了几乎所有东西:)

以上是关于如何将多个 UIDynamicItem 相互附加的主要内容,如果未能解决你的问题,请参考以下文章

如何将 .wav 格式的声音相互附加

UIDynamicItem 手动更新转换

如何将两个html文件和两个JavaScript文件相互附加?

将多个对象相互传递

具有非矩形边界的 UIDynamicItem

如何将多个 filter() 查询附加到一个变量中