问题描述
我试图通过让重力作用在一些 UIViews 上来为它们设置动画。理想情况下,每个视图都将停留在 UITableViewCell 边界内,并且它们会像边界一样从彼此和墙壁上弹开。但是,当我运行此代码时,UIView 只是在原地浮动,只有在另一个视图碰巧出现在同一位置时才会移动。
class AnimateTableViewCell: UITableViewCell {
private var animator: UIDynamicAnimator!
private var gravity: UIGravityBehavior!
private var collision: uicollisionbehavior!
private var views = [UIView]()
override func awakeFromNib() {
super.awakeFromNib()
}
override init(style: UITableViewCell.CellStyle,reuseIdentifier: String?) {
super.init(style: style,reuseIdentifier: reuseIdentifier)
animator = UIDynamicAnimator(referenceView: self.contentView)
let items = [UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill")]
for item in items {
let size = Int.random(in: 75 ... 180)
self.setUpView(view: UIView(frame: CGRect(x: 100,y: 100,width: size,height: size)),image: item!,size: size/2)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func applyGravity(to item: UIView) {
gravity = UIGravityBehavior(items: [item])
animator.addBehavior(gravity)
collision = uicollisionbehavior(items: views)
collision.translatesReferenceBoundsIntoBoundary = true
animator.addBehavior(collision)
let bounce = UIDynamicItemBehavior(items: views)
bounce.elasticity = 0.3
}
private func setUpView(view: UIView,image: UIImage,size: Int) {
contentView.addSubview(view)
view.backgroundColor = image.averageColor
view.layer.cornerRadius = view.frame.height/2
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.heightAnchor.constraint(equalToConstant: CGFloat(size)),imageView.widthAnchor.constraint(equalToConstant: CGFloat(size)),imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),])
views.append(view)
applyGravity(to: view)
}
}
解决方法
有两个主要问题。
首先,碰撞行为妨碍了您。注释掉这一行:
animator.addBehavior(collision)
现在至少你会看到重力的作用。
第二,你是说
gravity = UIGravityBehavior(items: [item])
animator.addBehavior(gravity)
多次,每个项目一次。那是错误的。您必须具有包含所有项目的一个重力行为。
仅通过重新排列您的一些代码并更改一些神奇数字,我就得到了一般到中等的结果;这应该让你开始,至少(我使用了一个只有一个单元格的表格视图,高度很高):
class AnimateTableViewCell: UITableViewCell {
private var animator: UIDynamicAnimator!
private var gravity = UIGravityBehavior()
private var collision = UICollisionBehavior()
private var views = [UIView]()
override func awakeFromNib() {
super.awakeFromNib()
}
override init(style: UITableViewCell.CellStyle,reuseIdentifier: String?) {
super.init(style: style,reuseIdentifier: reuseIdentifier)
animator = UIDynamicAnimator(referenceView: self.contentView)
let items = [UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill"),UIImage(systemName: "star.fill")]
for item in items {
let size = Int.random(in: 20...40)
self.setUpView(view: UIView(frame: CGRect(x: 100,y: 100,width: size,height: size)),image: item!,size: size)
}
animator.addBehavior(gravity)
collision.translatesReferenceBoundsIntoBoundary = true
animator.addBehavior(collision)
let bounce = UIDynamicItemBehavior(items: views)
bounce.elasticity = 0.3
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func applyGravity(to item: UIView) {
gravity.addItem(item)
collision.addItem(item)
}
private func setUpView(view: UIView,image: UIImage,size: Int) {
contentView.addSubview(view)
view.backgroundColor = .red
view.layer.cornerRadius = view.frame.height/2
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.heightAnchor.constraint(equalToConstant: CGFloat(size)),imageView.widthAnchor.constraint(equalToConstant: CGFloat(size)),imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),])
views.append(view)
applyGravity(to: view)
}
}