在同一 UIView 中多次检测到点击手势

Tap Gesture Detected Multiple Times in the same UIView

目前,我正在尝试将 UITapGestureRecognizer 添加到 UIView 以启动计时器。但是,每当我错误地多次点击 UIView 时,都会识别出多个手势并且计时器 运行 两次,或者比平时快好几倍。

我想确保 UIView 仅识别 1 个定时器动作/1 个点击手势,并且第二次点击将是多余的(稍后我将努力确保第二次点击“停止”定时器)。

我尝试阅读 ,但它并没有完全指导我如何防止第二次点击或根据状态自定义操作,我仍在努力弄清楚,但我卡在这个问题上了。

如果您对我如何解决此问题有任何见解,请提供帮助。

class ActiveExerciseTableViewCell: UITableViewCell, UITextFieldDelegate {
    
    var restTimer = Timer()
    var restTimeRemaining: Int = 180
    
    func setUpActiveExerciseUIViewLayout(){
        
        timerLabel.translatesAutoresizingMaskIntoConstraints = false
        timerLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        timerLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: (contentView.frame.height-tableviewContentViewTabBarHeight)*0.55).isActive = true
        timerLabel.widthAnchor.constraint(equalToConstant: contentView.frame.width * 0.7).isActive = true
        timerLabel.heightAnchor.constraint(equalToConstant: 80).isActive = true
        timerLabel.font = .boldSystemFont(ofSize: 64)
        
        
        activeExerciseTimerUIView.translatesAutoresizingMaskIntoConstraints = false
        activeExerciseTimerUIView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        activeExerciseTimerUIView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: (contentView.frame.height-tableviewContentViewTabBarHeight)*0.25).isActive = true
        activeExerciseTimerUIView.widthAnchor.constraint(equalToConstant: 225).isActive = true
        activeExerciseTimerUIView.heightAnchor.constraint(equalToConstant: 225).isActive = true
        
        
        let timerStartGesture = UITapGestureRecognizer(target: self, action: #selector(playTapped))
        timerStartGesture.numberOfTapsRequired = 1
        
        activeExerciseTimerUIView.addGestureRecognizer(timerStartGesture)
        activeExerciseTimerUIView.isUserInteractionEnabled = true
    }
    
    @objc func playTapped(_ sender: Any) {
        restTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(step), userInfo: nil, repeats: true)
    }
    
    @IBAction func pauseTapped(_ sender: Any) {
        restTimer.invalidate()
    }
    
    @IBAction func resetTapped(_ sender: Any) {
        restTimer.invalidate()
        restTimeRemaining = 180
        timerLabel.text = "\(restTimeRemaining)"
    }
    
    @objc func step() {
        if restTimeRemaining > 0 {
            restTimeRemaining -= 1
        } else {
            restTimer.invalidate()
            restTimeRemaining = 180
        }
        timerLabel.text = prodTimeString(time: TimeInterval(restTimeRemaining))
    }
    
    func prodTimeString(time: TimeInterval) -> String {
        let Minutes = Int(time) / 60 % 60
        let Seconds = Int(time) % 60
        
        return String(format: "%02d:%02d", Minutes, Seconds)
    }
}

使用布尔值处理状态变化:

class ActiveExerciseTableViewCell: UITableViewCell, UITextFieldDelegate {
    
    var restTimer = Timer()
    var restTimeRemaining: Int = 180
    var timerInitiated: Bool = false /// here!
    
    func setUpActiveExerciseUIViewLayout() {
        
        timerLabel.translatesAutoresizingMaskIntoConstraints = false
        timerLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        timerLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: (contentView.frame.height-tableviewContentViewTabBarHeight)*0.55).isActive = true
        timerLabel.widthAnchor.constraint(equalToConstant: contentView.frame.width * 0.7).isActive = true
        timerLabel.heightAnchor.constraint(equalToConstant: 80).isActive = true
        timerLabel.font = .boldSystemFont(ofSize: 64)
        
        
        activeExerciseTimerUIView.translatesAutoresizingMaskIntoConstraints = false
        activeExerciseTimerUIView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        activeExerciseTimerUIView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: (contentView.frame.height-tableviewContentViewTabBarHeight)*0.25).isActive = true
        activeExerciseTimerUIView.widthAnchor.constraint(equalToConstant: 225).isActive = true
        activeExerciseTimerUIView.heightAnchor.constraint(equalToConstant: 225).isActive = true
        
        
        let timerStartGesture = UITapGestureRecognizer(target: self, action: #selector(playTapped))
        timerStartGesture.numberOfTapsRequired = 1
        
        activeExerciseTimerUIView.addGestureRecognizer(timerStartGesture)
        activeExerciseTimerUIView.isUserInteractionEnabled = true
    }
    
    @objc func playTapped(_ sender: Any) {
        if !timerInitiated { /// check here
            restTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(step), userInfo: nil, repeats: true)
            self.timerInitiated = true
        }
    }
    
    @IBAction func pauseTapped(_ sender: Any) {
        restTimer.invalidate()
    }
    
    @IBAction func resetTapped(_ sender: Any) {
        restTimer.invalidate()
        restTimeRemaining = 180
        timerLabel.text = "\(restTimeRemaining)"
    }
    
    @objc func step() {
        if restTimeRemaining > 0 {
            restTimeRemaining -= 1
        } else {
            restTimer.invalidate()
            restTimeRemaining = 180
        }
        timerLabel.text = prodTimeString(time: TimeInterval(restTimeRemaining))
    }
    
    func prodTimeString(time: TimeInterval) -> String {
        let Minutes = Int(time) / 60 % 60
        let Seconds = Int(time) % 60
        
        return String(format: "%02d:%02d", Minutes, Seconds)
    }
}

如果 timerInitiated 布尔值是真,这意味着练习已经开始并且不会再安排任何计时器,除非布尔值被改变。