티스토리 뷰

 

오늘은 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를 사용하면 빠르게 구현할 수 있을 거 같다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/03   »
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
글 보관함