iOS/패스트캠퍼스(앱제작)
타이머 앱
soultreemk
2022. 5. 8. 13:41
주요기능
1. DispatchSourceTimer : 반복적 주기로 특정 작업을 수행 (핸들러 호출)
- Timer클래스 로도 구현 가능
- GCD api내의 DispatchSourceTimer 메소드로 구현함
2. UIView Animation
- view의 알파값을 조정하여 뷰가 사라지고 표시될때 자연스럽게 이동
- 이미지가 회전하도록 구현
//
// ViewController.swift
// pomodoro
//
// Created by YANG on 2022/05/06.
//
import UIKit
import AudioToolbox
enum TimerStatus {
case start
case pause
case end
}
class ViewController: UIViewController {
@IBOutlet weak var datePicker: UIDatePicker!
@IBOutlet weak var progressView: UIProgressView!
@IBOutlet weak var timerLabel: UILabel!
@IBOutlet weak var toggleBtn: UIButton!
@IBOutlet weak var cancelBtn: UIButton!
@IBOutlet weak var imageView: UIImageView!
var duration = 60
var timerStatus: TimerStatus = .end
var timer: DispatchSourceTimer?
var currentSeconds = 0
override func viewDidLoad() {
super.viewDidLoad()
self.configureToggleBtn()
}
func setTimerInfoViewVisible(isHidden: Bool) {
self.timerLabel.isHidden = isHidden
self.progressView.isHidden = isHidden
}
func configureToggleBtn() {
self.toggleBtn.setTitle("시작", for: .normal)
self.toggleBtn.setTitle("일시정지", for: .selected) // 버튼이 클릭되면 title 변경
}
func startTimer() {
if self.timer == nil {
self.timer = DispatchSource.makeTimerSource(flags: [], queue: .main)
self.timer?.schedule(deadline: .now(), repeating: 1) // 1초마다 반복
// 타이머가 동작할때마다 즉, 1초마다 handler내의 closure함수가 호출됨
self.timer?.setEventHandler(handler: { [weak self] in
guard let self = self else { return }
self.currentSeconds -= 1
let hour = self.currentSeconds / 3600
let minute = (self.currentSeconds % 3600) / 60
let seconds = (self.currentSeconds % 3600) % 60
// 화면에 표시
self.timerLabel.text = String(format: "%02d:%02d:%02d", hour, minute, seconds)
self.progressView.progress = Float(self.currentSeconds) / Float(self.duration)
// 이미지가 180도 변화
UIView.animate(withDuration: 0.5, delay: 0, animations: {
self.imageView.transform = CGAffineTransform(rotationAngle: .pi)
})
// 180도 변화하는 애니메이션이 끝난 후 360도 회전
UIView.animate(withDuration: 0.5, delay: 0.5, animations: {
self.imageView.transform = CGAffineTransform(rotationAngle: .pi * 2)
})
if self.currentSeconds <= 0 {
// 타이머가 종료
self.stopTimer()
AudioServicesPlaySystemSound(1005)
}
})
self.timer?.resume()
}
}
func stopTimer() {
if self.timerStatus == .pause {
self.timer?.resume()
}
// self.setTimerInfoViewVisible(isHidden: false)
// self.datePicker.isHidden = true
UIView.animate(withDuration: 0.5, animations: {
self.timerLabel.alpha = 0
self.progressView.alpha = 0
self.datePicker.alpha = 1
self.imageView.transform = .identity
})
self.toggleBtn.isSelected = false
self.cancelBtn.isEnabled = false
self.timer?.cancel()
self.timer = nil
}
@IBAction func tabCancleBtn(_ sender: Any) {
switch self.timerStatus {
case .start, .pause:
self.timerStatus = .end
self.cancelBtn.isEnabled = false
self.setTimerInfoViewVisible(isHidden: true)
self.datePicker.isHidden = false
self.toggleBtn.isSelected = false
default:
break
}
}
@IBAction func tabToggleBtn(_ sender: Any) {
self.duration = Int(self.datePicker.countDownDuration) // datePicker에서 설정한 시간을 초로 환산
switch self.timerStatus {
case .end:
self.currentSeconds = self.duration
self.timerStatus = .start
// self.setTimerInfoViewVisible(isHidden: false)
// self.datePicker.isHidden = true
// closure에 최종값 설정: 현재값에서 원하는 최종값으로 변화
UIView.animate(withDuration: 0.5, animations: {
self.timerLabel.alpha = 1
self.progressView.alpha = 1
self.datePicker.alpha = 0
})
self.toggleBtn.isSelected = true
self.cancelBtn.isEnabled = true
self.startTimer()
case .start:
self.timerStatus = .pause
self.toggleBtn.isSelected = false
self.timer?.suspend()
case .pause:
self.timerStatus = .start
self.toggleBtn.isSelected = true
self.timer?.resume()
}
}
}