如何将多个 UIDynamicItem 相互关联
How to attach multiple UIDynamicItems to each other
我正在尝试通过 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)
我做错了什么?
我不认为苹果音乐流派选择器使用 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 {
[=10=].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 { [=10=].center = CGPoint(x: [=10=].center.x + translation.x, y: [=10=].center.y + translation.y)}
case .possible, .cancelled, .failed:
break
case .ended:
circles.forEach { [=10=].center = CGPoint(x: [=10=].center.x + translation.x, y: [=10=].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
}
}
有关更多信息,我会观看 What's New in UIKit Dynamics and Visual Effects 来自 WWDC 2015
我正在尝试通过 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)
我做错了什么?
我不认为苹果音乐流派选择器使用 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 {
[=10=].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 { [=10=].center = CGPoint(x: [=10=].center.x + translation.x, y: [=10=].center.y + translation.y)}
case .possible, .cancelled, .failed:
break
case .ended:
circles.forEach { [=10=].center = CGPoint(x: [=10=].center.x + translation.x, y: [=10=].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
}
}
有关更多信息,我会观看 What's New in UIKit Dynamics and Visual Effects 来自 WWDC 2015