티스토리 뷰
오늘은 swift 스터디할 때 첫 프로젝트로 구현했던 스톱워치를 SwiftUI로 구현해 보았다.
swift로 만드는 첫 프로젝트이기도 하고 거의 언어를 몰라서 클론코딩에 가까운 수준이었다
지금 코드를 보니 누가 봐도 복붙 하거나 클론코딩 한 거 같다...
UIKit로 구현한 전체 코드
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var TimerLabel: UILabel!
@IBOutlet weak var startStopButton: UIButton!
@IBOutlet weak var resetButton: UIButton!
var timer:Timer = Timer()
var count:Int = 0
var timerCounting:Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// startStopButton.setTitleColor(UIColor.green, for:.normal)
startStopButton.tintColor = .white
}
@IBAction func resetTapped(_ sender: Any) {
let alert = UIAlertController(title: "Reset Timer?", message: "Are you sure you would like to reset the Timer?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "CANCEL", style: .cancel, handler: { (_) in
//do nothing
}))
alert.addAction(UIAlertAction(title: "YES", style: .default, handler: { (_) in
self.count = 0
self.timer.invalidate()
self.TimerLabel.text = self.makeTimeString(minutes: 0, seconds: 0)
//self.startStopButton.setTitle("START", for: .normal)
self.startStopButton.setImage(UIImage(systemName: "play.fill"), for: .normal)
self.startStopButton.setTitleColor(UIColor.green, for:.normal)
}))
self.present(alert, animated: true, completion: nil)
}
@IBAction func startStopTapped(_ sender: Any) {
if(timerCounting) {
timerCounting = false
timer.invalidate()
//startStopButton.setTitle("START", for: .normal)
self.startStopButton.setImage(UIImage(systemName: "play.fill"), for: .normal)
startStopButton.setTitleColor(UIColor.green, for:.normal)
}
else {
timerCounting = true
// startStopButton.setTitle("STOP", for:.normal)
//startStopButton.tintColor = .red
self.startStopButton.setImage(UIImage(systemName: "pause.fill"), for: .normal)
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerCounter), userInfo: nil, repeats: true)
}
}
@objc func timerCounter() -> Void {
count = count + 1
let time = secondsToHoursMinutesSeconds(seconds: count)
let timeString = makeTimeString(minutes: time.0, seconds: time.1)
TimerLabel.text = timeString
}
func secondsToHoursMinutesSeconds(seconds: Int) -> (Int, Int) {
return ( ((seconds % 3600) / 60), ((seconds % 3600) % 60))
}
func makeTimeString(minutes: Int, seconds: Int) -> String {
var timeString = ""
timeString += String(format: "%02d", minutes)
timeString += ":"
timeString += String(format: "%02d", seconds)
return timeString
}
}
구현방법

swiftUI로 구현한 방식은 우선 ZStack으로 전체 뷰를 잡아주고, 시간이 뜨는 text와 reset버튼만 있는 부분을 VStack으로 나눠주었다.
밑에 play, pause 버튼이 있는 뷰 전체를 HStack으로 나눠주었고 보라색 view, 초록색 view 각각을 ZStack으로 또 나누어주었다.
이렇게 view 덕지덕지 해서 구현하는 게 맞는 건가..? stack 도둑마냥 .. 싶지만 일단 swiftUI 초보자인 만큼 구현 성공에 의의를 두었다 ㅎ
StackView에 대해 정리한 게시글도 조만간 올리겠다!
타이머 설정하는 법은 UIKit로 stopwatch 구현했을 때의 코드를 주로 참고하였기에 따로 작성하지 않겠다.
swiftUI로 구현한 전체 코드
import SwiftUI
struct ContentView: View {
@ObservedObject var stopWatch = Stop_Watch()
var body: some View {
ZStack {
Color.black.ignoresSafeArea()
VStack(spacing: 0) {
VStack (alignment: .center){
Button("reset") {
self.stopWatch.reset()
}
.position(x:350, y:20)
.font(.system(size: 25.0))
let minutes = String(format: "%02d", stopWatch.counter / 60)
let seconds = String(format: "%02d", stopWatch.counter % 60)
let union = minutes + " : " + seconds
Text("\(union)")
.foregroundColor(.white)
.font(.custom("", size: 90))
.position(x:200, y:0)
}
GeometryReader { g in
HStack (spacing: 0){
ZStack {
Rectangle()
.fill(.purple)
Button(action: {
self.stopWatch.start()
}, label: {
Image(systemName: "play")
.foregroundColor(.white)
.font(.largeTitle)
})
}
.frame(width: g.size.width/2, height: 450)
ZStack {
Rectangle()
.fill(.green)
Button(action: {
self.stopWatch.stop()
}, label: {
Image(systemName: "pause")
.foregroundColor(.white)
.font(.largeTitle)
})
}
.frame(width: g.size.width/2, height: 450)
}
}
}
}
}
}
class Stop_Watch: ObservableObject {
@Published var counter: Int = 0
var timer = Timer()
func start() { //타이머 시작
self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
self.counter += 1
}
}
func stop() { // 타이머 중지
self.timer.invalidate()
}
func reset() { //타이머 초기화
self.counter = 0
self.timer.invalidate()
}
}
#Preview {
ContentView()
}
느낀 점
UIKit으로 할 때는 스토리보드로 작업하다 보니 view를 짤 때 다루기가 쉬웠는데 swiftUI로 구현하려다 보니 VStack, HStack, ZStack을 이용해서 정렬하고 view를 짜다 보니 조금 더 불편하게 느껴졌던 거 같다.
swiftUI도 시작한 지 얼마 안돼서 다루는 게 익숙하지는 않지만 구현하는데 자체는 시간이 오래 걸리지 않았던 거 같다.
확실히 UIKit보다 swiftUI를 사용해서 구현했을 때 코드가 간결해지는 걸 느껴서 뷰가 좀 더 복잡해지거나 여러 기능이 추가되었을 때 swiftUI를 사용하면 빠르게 구현할 수 있을 거 같다.
'iOS > SwiftUI' 카테고리의 다른 글
| [iOS/SwiftUI] Preview Crashed 해결방법 (0) | 2024.03.30 |
|---|---|
| [iOS/SwiftUI] DatePicker를 이용한 TaskEditor 만들기 (1) | 2024.02.29 |
| [iOS/SwiftUI] LazyVGrid를 활용하여 뷰 만들기 (1) | 2024.02.25 |
| [iOS/SwiftUI] List를 활용한 TodoList 만들기 (1) | 2024.02.07 |
| [iOS/SwiftUI] imagePicker 사용해서 프로필 만들기 (0) | 2024.02.02 |
- Total
- Today
- Yesterday
- 프로그래머스
- swiftUI
- ios
- SnapshotTest
- combine
- Xcode
- awakeFromNib
- detached task
- CoreData
- 코딩테스트
- 클로저
- rxswift
- closure
- UITest
- foundation models
- Fastlane
- ObservableObject
- UIKit
- 백준
- Task
- Swift Format
- Swift Concurrency
- SWIFT
- internal Combine
- 스위프트
- XCTest
- unstructed task
- asyne-let
- group tasks
- prepareForReuse
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | 31 |