ios - 如何在计时器暂停时捕获耗时

标签 ios swift xcode

我准备了一个倒计时计时器,这样用户就可以重新记录他们的练习季。除了一部分,我让它工作正常。允许用户暂停 session 。到目前为止代码的问题是定时器代码暂停但时间继续运行。

例如,如果用户将定时器设置为 5 分钟并点击开始按钮,则在中途用户点击暂停并等待 2 分钟(这意味着耗时现在为 7 分钟)定时器时显示的练习时间结束是 7 分钟而不是 5 分钟。如果用户取消 session 没关系,但这只是因为我设置了硬开始和结束时间。

我的问题是,如果用户暂停计时器,我该如何捕捉练习时间?

这是对 UI 的解释: timerLabel 包含运行时间 minutesLabel 显示用户设置计时器的分钟数 hoursLabel 显示用户将计时器设置为的小时数 有两个 slider 。一个用于设置分钟,一个用于设置小时 还有两个按钮。播放/取消按钮和暂停/恢复按钮

提前致谢!

import UIKit
import AVFoundation

class Practice_Timmer_VC: UIViewController
{
    @IBOutlet weak var navBar: UINavigationItem!
    @IBOutlet weak var viewLabel: DesignableLabel!
    @IBOutlet weak var timerLabel: DesignableLabel!
    @IBOutlet weak var theTabbar: UITabBar!
    @IBOutlet weak var minutesLabel: UILabel!
    @IBOutlet weak var hoursLabel: UILabel!

    var seconds: Int  = 60
    var timer = Timer()
    var isTimerRunning: Bool = false
    var resumeTapped: Bool  = false
    var theTime: String = ""

    var startTime: Date = Date()
    var endTime: Date = Date()

    var total: Int = 0

    var chimeSoundEffect: AVAudioPlayer?

    override func viewDidLoad()
    {
        super.viewDidLoad()

        theTabbar.selectedItem = theTabbar.items![4]

        view.backgroundColor = UIColor(patternImage: UIImage(named: "Carbon.png")!)

        startButton.isEnabled = true
        pauseButton.isEnabled = false

        populateTheTimer()

    }// End of viewDidLoad

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)

        startButton.setImage(UIImage(named: "Play"), for: .normal)
    }

    func populateTheTimer()
    {
        let theName = ModelData.getTheTrickName()
        navBar.title = theName
    }

    func getTheDifference(start: Date, end: Date)
    {
        let theFormatter = DateComponentsFormatter()
        theFormatter.allowedUnits = [.hour, .minute]
        theFormatter.unitsStyle = .full

        theTime = theFormatter.string(from: start, to: end) ?? ""
    }

    func formattedDate() -> String
    {
        let formatter = DateFormatter()
        let date = Date()
        formatter.locale = Locale.current
        formatter.dateStyle = .medium
        return formatter.string(from: date)
    }

    func timeString(time: TimeInterval) -> String
    {
        let hours = Int(time) / 3600
        let minutes = Int(time) / 60 % 60
        let seconds = Int(time) % 60

        return String(format:"%02i:%02i:%02i", hours, minutes, seconds)
    }

    func runTimer()
    {
        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(self.updateTimer)), userInfo: nil, repeats: true)

        isTimerRunning = true
        pauseButton.isEnabled = true
    }

    @objc func updateTimer()
    {
        if seconds < 1
        {
            timer.invalidate()

            endTime = Date()

            getTheDifference(start: startTime, end: endTime)

            startButton.setImage(UIImage(named: "Play"), for: .normal)
            startButton.isEnabled = true
            pauseButton.isEnabled = false

            playTheSound()
            showAlert()

        } else {
            seconds -= 1
            timerLabel.text = timeString(time: TimeInterval(seconds))
        }
    }

    func showAlert()
    {
        let theAlert = UIAlertController(title: "Practice Ended", message: "\(formattedDate())\nPracticed for: \(theTime)", preferredStyle: .alert)

        let saveTheInfo = UIAlertAction(title: "Save Practice", style: .default) { (saveAction) in
            self.gotoAddEdit()
        }

        let cancel = UIAlertAction(title: "Cancel", style: .cancel) { (cancelAction) in

        }

        theAlert.addAction(saveTheInfo)
        theAlert.addAction(cancel)

        present(theAlert, animated: true)
    }

    func playTheSound()
    {
        let path = Bundle.main.path(forResource: "chime.mp3", ofType: nil)!
        let theURL = URL(fileURLWithPath: path)

        do {
            chimeSoundEffect = try AVAudioPlayer(contentsOf: theURL)
            chimeSoundEffect?.play()
        } catch {

        }
    }

    func gotoAddEdit()
    {
        let sb = UIStoryboard(name: "Main", bundle: nil)
        if let addEdit = sb.instantiateViewController(withIdentifier: "Practice_Log_VC") as? Practice_Log_VC
        {

            addEdit.passData = "\(formattedDate())\nPracticed for: \(theTime)"
            addEdit.delegate = self as? Timer2PracticeLog_Delegate

            self.navigationController?.pushViewController(addEdit, animated: ModelData.isAnimation())
            self.navigationController?.view.semanticContentAttribute = .forceLeftToRight
        }
    }

    @IBOutlet weak var startButton: DesignableButton!
    @IBAction func startButtonTapped(_ sender: DesignableButton)
    {
        let minutes2Seconds = Int(minutesSliderOutlet.value) * 60
        let hours2Seconds = Int(hoursSliderOutlet.value) * 3600

        seconds = Int(minutes2Seconds + hours2Seconds)

        if isTimerRunning == false // Start
        {
            if seconds > 0
            {
                startTime = Date()

                sender.setImage(UIImage(named: "Cancel_Video"), for: .normal)
                runTimer()

            } else {
                view.sendConfirmationAlert(theTitle: "Error! Practice time is set to 0.", theMessage: "Please set the practice time.", buttonTitle: "OK")
                minutesSliderOutlet.value = 1
                minutesLabel.text = "1 Minute"
            }

        } else { // Cancel

            endTime = Date()

            timer.invalidate()

            seconds = 0

            getTheDifference(start: startTime, end: endTime)

            sender.setImage(UIImage(named: "Play"), for: .normal)

            minutesSliderOutlet.value = 1
            minutesLabel.text = "1 Minute"
            hoursSliderOutlet.value = 0
            hoursLabel.text = "0 Hours"

            timerLabel.text = timeString(time: TimeInterval(seconds))
            isTimerRunning = false
            pauseButton.isEnabled = false

            showAlert()
        }
    }

    @IBOutlet weak var pauseButton: DesignableButton!
    @IBAction func pauseButtonTapped(_ sender: DesignableButton)
    {
        if resumeTapped == false
        {
            timer.invalidate()
            resumeTapped = true
            sender.setImage(UIImage(named: "Resume"), for: .normal)

        } else {
            runTimer()
            resumeTapped = false
            sender.setImage(UIImage(named: "Pause"), for: .normal)
        }
    }

    @IBOutlet weak var minutesSliderOutlet: UISlider!
    @IBAction func minuteSlider(_ sender: UISlider)
    {
        let minutes = Int(sender.value)
        if minutes > 1
        {
            minutesLabel.text = String(minutes) + " Minutes"
        } else {
            minutesLabel.text = String(minutes) + " Minute"
        }
    }

    @IBOutlet weak var hoursSliderOutlet: UISlider!
    @IBAction func hoursSlider(_ sender: UISlider)
    {
        let hours = Int(sender.value)
        if hours > 1
        {
            hoursLabel.text = String(hours) + " Hours"
        } else {
            hoursLabel.text = String(hours) + " Hour"
        }
    }

}// End of Class

最佳答案

获取用户暂停应用的时间作为新的date(),以及用户恢复应用的时间。获取这两个日期/时间之间的差异,并从总时间中减去该差异以获得正确的练习总时间。

例如,您可以使用一个变量来跟踪总暂停时间:

var totalPauseTime: TimeInterval = 0
var pauseStartTime: Date?

每次用户点击暂停按钮恢复时(在之前点击暂停按钮之后),它都会重新计算:

@IBAction func pauseButtonTapped(_ sender: DesignableButton)
    {
        if resumeTapped == false
        {
            pauseStartTime = Date() 
            timer.invalidate()
            resumeTapped = true
            sender.setImage(UIImage(named: "Resume"), for: .normal)

        } else {
            if let pauseStartTime = pauseStartTime {
                totalPauseTime += Date().timeIntervalSinceReferenceDate - pauseStartTime.timeIntervalSinceReferenceDate
            }
            runTimer()

            resumeTapped = false
            sender.setImage(UIImage(named: "Pause"), for: .normal)
        }
    }

还没有实际测试过上面的代码,但它应该给出了一个想法。然后在代码中计算总 session 时间的地方减去 totalPauseTime。

关于ios - 如何在计时器暂停时捕获耗时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58514984/

相关文章:

ios - 禁用 UIPickerView 中的特定行值

ios - 搜索自定义表格 View 单元格不起作用并返回 nil

iOS 9 和 XCode 7 dylib 问题

ios - iPad 调试过程中空气结冰

ios - 什么是UDID?仅添加 1 台设备后,我可以在其他 iOS 设备上测试游戏吗?

ios - 打开简历。以灰度而不是 RGB 形式返回的图像

ios - 如何从 cellForItemAtIndexPath 设置 UICollectionViewCell 高度?

ios - 'Pods-App'目标具有传递依赖项,包括在快速框架中使用GTM时包括静态二进制文件的传递依赖项

ios - SKSpriteNode 能识别手势吗?

objective-c - IP地址? - cocoa