Reputation: 319
i have made a stop watch using Timer in this app and added start stop button to pause and play the same. When the press button is pressed, it is sent to a function which invalidates the timer and it should stop. But Strangely Enough When The Stop Button Is Pressed, Instead Of Stopping The Timer Somehow Speeds Up i have not changed the time interval other than once just declaring it.
i have tried to disabled the start button once it is pressed and even hide it. also tried changing the time interval but nothing works. the more i press the start stop button , the more it speeds up and starts going much faster than the mentioned time interval.
startButton.frame = CGRect(x: 0, y: UIScreen.main.bounds.height * 0.9 , width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 0.1)
startButton.setTitle("Start Timer", for: .normal)
self.view.addSubview(startButton)
startButton.setTitleColor(.white , for: .normal)
startButton.backgroundColor = .red
startButton.addTarget(self, action: #selector(playButton(_:)), for: .allTouchEvents)
stopButton.frame = CGRect(x: 0, y: UIScreen.main.bounds.height * 0.9 , width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 0.1)
stopButton.setTitle("Stop Timer", for: .normal)
stopButton.setTitleColor(.white , for: .normal)
stopButton.backgroundColor = .red
stopButton.addTarget(self, action: #selector(pauseButton(_:)), for: .allTouchEvents)
@objc func playButton(_ sender : Any)
{
timer = Timer.scheduledTimer(timeInterval: 1, target: self , selector: #selector(updateTimer), userInfo: nil, repeats: true)
startButton.isEnabled = false
stopButton.isEnabled = true
isRunning = true
self.view.addSubview(stopButton)
startButton.isHidden = true
stopButton.isHidden = false
}
@objc func pauseButton(_ sender: Any) {
self.view.addSubview(startButton)
timer.invalidate()
stopButton.isHidden = true
startButton.isHidden = false
startButton.isEnabled = true
stopButton.isEnabled = false
isRunning = false
}
@objc func updateTimer(_ sender : Any)
{
counter += 0.1
titleLabel.text = String(format: "%.1f", counter)
}
Upvotes: 1
Views: 399
Reputation: 1533
You have 2 correct answers already, but I'll throw in my 2p as I think the premises you've started on hasn't been correct.
Your biggest mistake is having 2 buttons in the first place. You would not have had the issue if you only had one buttons and styled it as needed.
class MyTest {
let magicButton = UIButton()
let timer: Timer?
override viewDidLoad() {
super.viewDidLoad()
// Setup Button
magicButton.addTarget(self, action: #selector(buttonPress(_:)), for: .allTouchEvents)
magicButton.setTitleColor(.white , for: .normal)
magicButton.frame = yourFrame
view.addSubview(magicButton)
customiseButton()
}
@objc private func buttonPress() {
if timer == nil {
timer = Timer.scheduledTimer(timeInterval: 1, target: self , selector: #selector(updateTimer), userInfo: nil, repeats: true)
} else {
timer.invalidate()
}
customiseButton()
}
private func customiseButton() {
let isStartButton = timer == nil
let buttonTitle = isStartButton ? "Start" : "Stop"
let buttonBackgroundColor: UIColor = isStartButton ? .green : .red
magicButton.setTitle(buttonTitle, for: .normal)
magicButton.backgroundColor = buttonBackgroundColor
}
}
// add updateTimer function too
This way you have less code to maintain and no conflict between stuff being hidden / shown, so fewer things that could go wrong. The magic is happening in the buttonPress method where if a timer is started you stop it, otherwise you start one, followed by a quick update to the button UI.
Upvotes: 1
Reputation: 650
As far as I can recognize, you have 2 mistakes.
First one is mentioned by the other answer. It is a true suggestion that you shouldn't always add a new UIButton and should use just hide/unhide property for each button.
Second mistake is on how you add a target. You are using .allTouchEvents, however you might intent to use .touchUpInside as your control state.
Kindly see the below corrected code for your reference:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var titleLabel: UILabel!
var startButton: UIButton!
var stopButton: UIButton!
var timer: Timer!
var counter: Double = 0.0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
startButton = UIButton(frame: CGRect(x: 0, y: UIScreen.main.bounds.height * 0.9 , width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 0.1))
startButton.setTitle("Start Timer", for: .normal)
startButton.setTitleColor(.white , for: .normal)
startButton.backgroundColor = .red
startButton.addTarget(self, action: #selector(playButton(_:)), for: .touchUpInside)
self.view.addSubview(startButton)
self.startButton.isHidden = false
stopButton = UIButton(frame: CGRect(x: 0, y: UIScreen.main.bounds.height * 0.9 , width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 0.1))
stopButton.setTitle("Stop Timer", for: .normal)
stopButton.setTitleColor(.white , for: .normal)
stopButton.backgroundColor = .red
stopButton.addTarget(self, action: #selector(pauseButton(_:)), for: .touchUpInside)
self.view.addSubview(stopButton)
self.stopButton.isHidden = true
}
@objc func playButton(_ sender : Any) {
timer = Timer.scheduledTimer(timeInterval: 1, target: self , selector: #selector(updateTimer), userInfo: nil, repeats: true)
startButton.isEnabled = false
stopButton.isEnabled = true
startButton.isHidden = true
stopButton.isHidden = false
}
@objc func pauseButton(_ sender: Any) {
timer.invalidate()
stopButton.isHidden = true
startButton.isHidden = false
startButton.isEnabled = true
stopButton.isEnabled = false
}
@objc func updateTimer(_ sender : Any)
{
counter += 0.1
titleLabel.text = String(format: "%.1f", counter)
}
}
Upvotes: 1
Reputation: 470
Try to add both the buttons at the same time by hidding the stop button and just hide and unhide the buttons on button click. Your play button method is running every time, when you are trying to stop the timer
Upvotes: 1