如何在 UITableViewCell 中向 UIViews 添加重力?

问题描述

我试图通过让重力作用在一些 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)
    }
}