iosswiftuiviewuikituitapgesturerecognizer

Tap Gesture not working on the Circle Swift


I'm creating a single-page game where you select a circle, and the score level increases. I've almost completed it, but my tap gesture is not working on the circles. I've tried the code below, but it's not working. Please check the code below.

import UIKit
import AVFoundation

class Demogame: UIViewController {

    @IBOutlet weak var scoreLabel: UILabel!

    var score = 0
    var isGameOver = false

    override func viewDidLoad() {
        super.viewDidLoad()
        startGame()
    }

    func startGame() {
        score = 0
        scoreLabel.text = "Score: \(score)"
        isGameOver = false

        // Create a timer to spawn circles
        Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true) { timer in
            if !self.isGameOver {
                self.spawnCircle()
            } else {
                timer.invalidate()
            }
        }
    }

    func spawnCircle() {
        let circleSize = CGSize(width: 50, height: 50)
        let circleView = UIView(frame: CGRect(origin: CGPoint(x: CGFloat.random(in: 50...view.frame.width - circleSize.width - 50),
                                                              y: CGFloat.random(in: 100...view.frame.height - circleSize.height - 50)),
                                              size: circleSize))

        circleView.backgroundColor = UIColor.random()
        circleView.layer.cornerRadius = circleSize.width / 2
        view.addSubview(circleView)

        // Add a tap gesture recognizer to each circle
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        circleView.addGestureRecognizer(tapGesture)

        // Animate the circle's appearance and disappearance
        UIView.animate(withDuration: 3.0, animations: {
            circleView.alpha = 0.0
        }) { (completed) in
            if completed {
                circleView.removeFromSuperview()
            }
        }
    }

    @objc func handleTap(_ sender: UITapGestureRecognizer) {
        if isGameOver {
            return
        }

        if let tappedView = sender.view {
            tappedView.removeFromSuperview()
            score += 1
            scoreLabel.text = "Score: \(score)"
        }
    }
}

extension UIColor {
    static func random() -> UIColor {
        return UIColor(
            red: CGFloat.random(in: 0.0...1.0),
            green: CGFloat.random(in: 0.0...1.0),
            blue: CGFloat.random(in: 0.0...1.0),
            alpha: 1.0
        )
    }
}

Question: How to tap gesture working on circles and increase the score level?

Can someone please explain to me how to do this, I've tried with the above code but have no results yet. Please Correct me if I'm doing wrong.

Any help would be greatly appreciated


Solution

  • Views - buttons, labels, image views, plain views, etc - do not receive touches when the .alpha is less than 0.01

    What may not be obvious is that when we write an animation block like this:

    UIView.animate(withDuration: 3.0, animations: {
        circleView.alpha = 0.0
    })
    

    UIKit immediately evaluates the instructions inside the block and then calculates the animation visual effect.

    So, as soon as that animation starts UIKit considers the circleView to have an .alpha of 0.0 -- so, no touch event / tap gesture.

    The other issue is that, by default, you cannot interact with UI elements during the animation.

    You can fix that by setting the animation options to .allowUserInteraction.

    If you change your animation block to this:

    UIView.animate(withDuration: 3.0, delay: 0.0, options: .allowUserInteraction, animations: {
        circleView.alpha = 0.05
    }, completion: { b in
        if b {
            circleView.removeFromSuperview()
        }
    })
    

    You should now be able to tap the circles.