Swift 계산기 앱 만들기 _ 2

STONE·2024년 9월 30일

Swift_Ios

목록 보기
4/44

계산기 앱 만들어보기

import SwiftUI

enum ButtonType: String {
    case first = "1", second = "2", third = "3", forth = "4", fifth = "5"
    case sixth = "6", seventh = "7", eighth = "8", nineth = "9", zero = "0"
    case dot = ".", equal = "=", plus = "+", minus = "-", multiple = "*", devide = "/"
    case percent = "%", opposite = "+/-", clear = "C"
    
    var backgroundColor: Color {
        switch self {
        case .first, .second, .third, .forth, .fifth, .sixth, .seventh, .eighth, .nineth, .zero, .dot:
            return Color("NumberButton")
        case .plus, .minus, .multiple, .devide, .equal:
            return Color.orange
        case .clear, .opposite, .percent:
            return Color.gray
        }
    }
    
    var forgroundColor: Color {
        switch self {
        case .first, .second, .third, .forth, .fifth, .sixth, .seventh, .eighth, .nineth, .zero, .dot:
            return Color.white
        case .plus, .minus, .multiple, .devide, .equal:
            return Color.white
        case .clear, .opposite, .percent:
            return Color.black
        }
    }
}

struct ContentView: View {
    
    @State private var totalNumber: String = "0"       // 화면에 표시되는 값
    @State private var currentExpression: String = ""  // 내부적으로 수식을 저장하는 변수
    @State private var didCalculate: Bool = false      // 계산 완료 여부
    
    private let buttonData: [[ButtonType]] = [
        [ .clear , .opposite , .percent , .devide ],
        [ .seventh , .eighth , .nineth , .multiple ],
        [ .forth , .fifth , .sixth , .minus ],
        [ .first , .second , .third , .plus ],
        [ .zero , .dot , .equal ]
    ]
    
    var body: some View {
        
        ZStack {
            Color.black.ignoresSafeArea(.all)
            
            VStack {
                Spacer()
                HStack {
                    Spacer()
                    // 수식 표시 (작은 폰트)
                    Text(currentExpression)
                        .padding()
                        .font(.system(size: 24)) // 작은 폰트 크기
                        .foregroundColor(.white)
                        .lineLimit(1)
                        .minimumScaleFactor(0.5)
                        .frame(maxWidth: .infinity, alignment: .trailing) // 오른쪽 정렬
                }

                
                HStack {
                    Spacer()
                    // 숫자 및 계산 결과를 표시
                    Text(totalNumber)
                        .padding()
                        .font(.system(size: 73))
                        .foregroundColor(.white)
                        .lineLimit(1)
                        .minimumScaleFactor(0.5)
                }
                
                ForEach(buttonData, id: \.self) { line in
                    HStack {
                        ForEach(line, id: \.self) { row in
                            Button {
                                handleInput(row)
                            } label: {
                                Text(row.rawValue)
                                    .frame(width: row == .zero ? 160 : 80, height: 80)
                                    .background(row.backgroundColor)
                                    .cornerRadius(40)
                                    .foregroundColor(row.forgroundColor)
                                    .font(.system(size: 33))
                            }
                        }
                    }
                }
            }
        }
        .padding()
    }
    
    func handleInput(_ button: ButtonType) {
        switch button {
        case .clear:
            totalNumber = "0"
            currentExpression = ""
            didCalculate = false
        case .plus, .minus, .multiple, .devide:
            if didCalculate {
                currentExpression = totalNumber // 계산된 결과로 새로운 수식 시작
                didCalculate = false
            }
            currentExpression += button.rawValue
            totalNumber = button.rawValue // 연산자 표시
        case .equal:
            // 수식을 직접 계산
            totalNumber = calculateExpression(currentExpression)
            didCalculate = true
            currentExpression = totalNumber // 다음 연산을 위해 결과를 저장
        case .percent:
            if let number = Double(totalNumber) {
                totalNumber = formatResult(number / 100)
                currentExpression = totalNumber
            }
        case .opposite:
            if let number = Double(totalNumber) {
                totalNumber = formatResult(number * -1)
                currentExpression = totalNumber
            }
        default:
            if didCalculate {
                totalNumber = button.rawValue
                currentExpression = button.rawValue
                didCalculate = false
            } else {
                if totalNumber == "0" || totalNumber == "+" || totalNumber == "-" || totalNumber == "*" || totalNumber == "/" {
                    totalNumber = button.rawValue
                } else {
                    totalNumber += button.rawValue
                }
                currentExpression += button.rawValue
            }
        }
    }
    
    func calculateExpression(_ expression: String) -> String {
        let expressionWithSpaces = expression.replacingOccurrences(of: "+", with: " + ")
            .replacingOccurrences(of: "-", with: " - ")
            .replacingOccurrences(of: "*", with: " * ")
            .replacingOccurrences(of: "/", with: " / ")

        let components = expressionWithSpaces.split(separator: " ")
        
        var values: [Double] = []
        var operations: [String] = []
        
        // 우선순위에 따라 계산
        for component in components {
            if let value = Double(component) {
                values.append(value)
            } else {
                operations.append(String(component))
            }
        }
        
        // 먼저 곱셈과 나눗셈을 수행
        var result: Double = values[0]
        
        for i in 0..<operations.count {
            let operation = operations[i]
            let nextValue = values[i + 1]
            
            switch operation {
            case "*":
                result *= nextValue
            case "/":
                result /= nextValue
            case "+":
                result += nextValue
            case "-":
                result -= nextValue
            default:
                break
            }
        }
        
        return formatResult(result)
    }

    // 결과를 포맷팅하는 함수
    func formatResult(_ result: Double) -> String {
        if result.truncatingRemainder(dividingBy: 1) == 0 {
            return String(Int(result)) // 정수 부분만 반환
        } else {
            return String(result) // 실수형 그대로 반환
        }
    }
}

#Preview {
    ContentView()
}

추가사항

  • /, +, -등 계산기호 기능 추가
  • 상단에 수식 전체 미리보기 추가
  • 복합연산 가능

수정사항

  • 아이폰 전체 백그라운드 컬러 지정 아직도 방법 못찾음
profile
흠...?

0개의 댓글