前提・実現したいこと
現在、swiftにてカウントダウンタイマーを作成しています。実現したい事としてはユーザーがインターバルを複数セットし、セットしたインターバルが過ぎた時点で通知をし、次のインターバルに移り、トータルの残り時間が0秒になったらタイマーを終了する機能を作成中です。
例)セットされたインターバル:20秒→1分→30秒
流れ:ユーザーがタイマーをスタート→20秒のタイマーがスタート→20秒タイマーが0秒でになったタイミングで音が鳴り、それと同時に1分タイマーがスタート→1分タイマーが0秒でになったタイミングで音が鳴り、それと同時に30秒タイマーがスタート→30秒タイマーが0秒になったら音が鳴り終了
発生している問題・エラーメッセージ
現在はそれぞれのインターバルを配列に格納し、上記のことを実装できないかと考えています。そのためには配列内の最初の要素(20)に対してTimerをスタートさせ、その要素が0になった時に次のインデックスに移り、それに対応している要素(60)のカウントダウンをスタートさせるようにしたいのですが、そのやり方がリサーチをしても見つかりません。配列での実装に固執しているわけではありませんので、配列に格納しなくとも上記のことが実装することが可能であれば、その方法もご教示いただけると幸いです。
コード
下記のコードではセットされた合計時間のカウントダウンの実装+セットされた各インターバルをラベルに表示のみ。そして、終了3秒前からカウントダウンの音源を流すようにしている。
import UIKit import AVFoundation import Foundation class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource{ @IBOutlet weak var pickerOutlet: UIPickerView! @IBOutlet weak var intervalOutlet: UILabel! @IBOutlet weak var currentIntervalOutlet: UILabel! @IBOutlet weak var timeOutlet: UILabel! var count = 0 var audioPlayer = AVAudioPlayer() var timer = Timer() var intervalTimer = Timer() let dataList = [[Int](0...24), [Int](0...60), [Int](0...60)] var hourList: [Int] = [] var minList: [Int] = [] var secList: [Int] = [] var intervalList: [String] = [] var currentIntervalList: [Int] = [] var totalTime = 0 var isPause = false var isStarted = false override func viewDidLoad() { super.viewDidLoad() pickerOutlet.delegate = self pickerOutlet.dataSource = self do { let audioPath = Bundle.main.path(forResource: "sound", ofType: ".mp3") try audioPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath!)) } catch { } } func numberOfComponents(in pickerView: UIPickerView) -> Int { return dataList.count } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { return dataList[component].count } func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { return String(dataList[component][row]) } func pickerView(_ pickerView: UIPickerView, widthForComponent component:Int) -> CGFloat { return pickerOutlet.bounds.width * 1/4 } @IBOutlet weak var setOutlet: UIButton! @IBAction func set(_ sender: UIButton) { let selectedRow1 = self.pickerOutlet.selectedRow(inComponent: 0) let selectedRow2 = self.pickerOutlet.selectedRow(inComponent: 1) let selectedRow3 = self.pickerOutlet.selectedRow(inComponent: 2) let hours = dataList[0][selectedRow1] let mins = dataList[1][selectedRow2] let secs = dataList[2][selectedRow3] let total = hours * 3600 + mins * 60 + secs currentIntervalList.append(total) if (hours != 0 && mins != 0 && secs != 0) { let interval = String(hours) + "h" + String(mins) + "m" + String(secs) + "s" intervalList.append(interval) } else if (hours != 0 && mins != 0 && secs == 0) { let interval = String(hours) + "h" + String(mins) + "m" intervalList.append(interval) } else if (hours != 0 && mins == 0 && secs == 0) { let interval = String(hours) + "h" intervalList.append(interval) } else if (hours == 0 && mins != 0 && secs != 0) { let interval = String(mins) + "m" + String(secs) + "s" intervalList.append(interval) } else if (hours == 0 && mins != 0 && secs == 0) { let interval = String(mins) + "m" intervalList.append(interval) } else if (hours == 0 && mins == 0 && secs != 0) { let interval = String(secs) + "s" intervalList.append(interval) } hourList.append(hours) minList.append(mins) secList.append(secs) var totalHours = 0; for hour in hourList { totalHours += hour } var totalMins = 0; for min in minList { totalMins += min } var totalSecs = 0; for sec in secList { totalSecs += sec } let hoursDisplayed = String(format: "%02d", totalHours) let minsDisplayed = String(format: "%02d", totalMins) let secsDisplayed = String(format: "%02d", totalSecs) intervalOutlet.text = intervalList.joined(separator: ",") timeOutlet.text = "(hoursDisplayed) : (minsDisplayed) : (secsDisplayed)" startOutlet.isEnabled = true backOutlet.isEnabled = true } @IBOutlet weak var startOutlet: UIButton! @IBAction func start(_ sender: UIButton) { if (!isStarted) { var hour = 0; for h in hourList { hour += h } var min = 0; for m in minList { min += m } var sec = 0; for s in secList { sec += s } count = hour * 3600 + min * 60 + sec isStarted = true if !isPause { timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.counter), userInfo: false, repeats: true) startOutlet.setTitle("Pause", for: UIControl.State.normal) isPause = true } else if isPause { timer.invalidate() isPause = false startOutlet.setTitle("Start", for: UIControl.State.normal) } } else { if !isPause { timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.counter), userInfo: false, repeats: true) startOutlet.setTitle("Pause", for: UIControl.State.normal) isPause = true } else if isPause { timer.invalidate() isPause = false startOutlet.setTitle("Start", for: UIControl.State.normal) } } setOutlet.isHidden = true backOutlet.isHidden = true pickerOutlet.isHidden = true } @objc func counter(){ count -= 1 var countCopy = count var hour = 0 var min = 0 var sec = 0 hour = countCopy / 3600 countCopy %= 3600 min = countCopy / 60 countCopy %= 60 sec = countCopy let Hour = String(format: "%02d", hour) let Min = String(format: "%02d", min) let Sec = String(format: "%02d", sec) timeOutlet.text = "(Hour) : (Min) : (Sec)" if (count == 3) { audioPlayer.play() } if (count == 0) { timer.invalidate() startOutlet.isEnabled = false } } }
補足情報(FW/ツールのバージョンなど)
Swift: 4.2
Xcode: 10.1
現在のUI
回答1件
あなたの回答
tips
プレビュー