4

As the user taps on superview I am detecting it via UITapGestureRecognizer and calling below function to create a UIImage view, add it to superview, add gravity to it and let it fall out of the superview.

Problem is that if the user taps again while the first UIImage is still on the screen, first image halts in place and the second UIImage starts falling. What is the best way to let multiple UIImage fall independently on the screen.

Secondly, I feel, I should be removing these UIImage from superview to conserve memory (as there could be hundreds of taps but I cant figure out how to automatically remove a UIImage as soon as it is out of the screen.

Help in swift please.

func dropBall(tapLocation:CGPoint) {
    let ball = UIImageView(image: UIImage(named: "White50.png"))
    ball.frame = CGRect(origin: CGPoint(x:tapLocation.x-25,y:tapLocation.y-25), size: CGSize(width:50,height:50))
    view.addSubview(ball)

    animator = UIDynamicAnimator(referenceView: self.view)
    gravity = UIGravityBehavior(items: [ball])
    animator.addBehavior(gravity)
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
Kashif
  • 4,642
  • 7
  • 44
  • 97

1 Answers1

8

The reason the first animation stops is that when you call this again, you are instantiating a new animator and releasing the old one. You should instantiate the animator only once. Likewise, you should instantiate gravity just once.

In terms of stopping the behavior once the view is off screen, one technique is to add an action block for the behavior, iterate through the behavior's items and see if each is still on screen, and remove the item from the behavior's list of items when the item falls off screen.

override func viewDidLoad() {
   super.viewDidLoad()

    animator = UIDynamicAnimator(referenceView: view)

    gravity = UIGravityBehavior()
    gravity.action = { [unowned self] in
        let itemsToRemove = self.gravity.items.filter() { !CGRectIntersectsRect(self.view.bounds, $0.frame) }
        for item in itemsToRemove {
            self.gravity.removeItem(item as UIDynamicItem)
            item.removeFromSuperview()
        }
    }
    animator.addBehavior(gravity)
}

Now, to give an item gravity, just add the item to the gravity behavior and it will automatically be removed when it falls out of view:

gravity.addItem(ball)
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • by moving the "animator = ...." line to view did load, first problem is solved, now all balls are dropping simultaneously. Can you please explain how to add action though. – Kashif Dec 26 '14 at 14:39
  • and that is causing warning: "Multiple gravity behavior per animator is undefined and may assert in the future" – Kashif Dec 26 '14 at 14:48
  • @user4293473 Yeah, I just saw that. So add gravity once, and then just add item to the gravity's `items` array. And define `action` that removes items when the item's `frame` no longer intersects the `bounds` of its `superview`. See revised answer. – Rob Dec 26 '14 at 15:05
  • I know this is an old question but it solved my problem. I was struggling from last 2 hours. Thanks @Rob – Jigaroza287 Jul 31 '16 at 09:18