Swiftui 计算器 连续计算

Swiftui Calculator Continuous calculation

我想在我的应用程序中练习真正的ios计算器并且可以连续计算

当我点击添加按钮时,我想可以 calculated.But 现在当我点击添加时我的值无法真正自动计算 button.I 不知道这个问题。

我应该如何更改我的代码?

这是我的 ContentView.swift:

import SwiftUI

enum CalcButton: String {
    case one = "1"
    case two = "2"
    case three = "3"
    case four = "4"
    case five = "5"
    case six = "6"
    case seven = "7"
    case eight = "8"
    case nine = "9"
    case zero = "0"
    case add = "+"
    case subtract = "-"
    case divide = "รท"
    case mutliply = "x"
    case equal = "="
    case clear = "AC"
    case decimal = "."
    case percent = "%"
    case negative = "-/+"

    var buttonColor: Color {
        switch self {
        case .add, .subtract, .mutliply, .divide, .equal:
            return .orange
        case .clear, .negative, .percent:
            return Color(.lightGray)
        default:
            return Color(UIColor(red: 55/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1))
        }
    }
}

enum Operation {
    case add, subtract, multiply, divide, none
}

struct ContentView: View {

    @State var value = "0"
    @State var runningNumber = 0
    @State var currentOperation: Operation = .none

    let buttons: [[CalcButton]] = [
        [.clear, .negative, .percent, .divide],
        [.seven, .eight, .nine, .mutliply],
        [.four, .five, .six, .subtract],
        [.one, .two, .three, .add],
        [.zero, .decimal, .equal],
    ]

    var body: some View {
        ZStack {
            Color.black.edgesIgnoringSafeArea(.all)

            VStack {
                Spacer()

                // Text display
                HStack {
                    Spacer()
                    Text(value)
                        .bold()
                        .font(.system(size: 100))
                        .foregroundColor(.white)
                }
                .padding()

                // Our buttons
                ForEach(buttons, id: \.self) { row in
                    HStack(spacing: 12) {
                        ForEach(row, id: \.self) { item in
                            Button(action: {
                                self.didTap(button: item)
                            }, label: {
                                Text(item.rawValue)
                                    .font(.system(size: 32))
                                    .frame(
                                        width: self.buttonWidth(item: item),
                                        height: self.buttonHeight()
                                    )
                                    .background(item.buttonColor)
                                    .foregroundColor(.white)
                                    .cornerRadius(self.buttonWidth(item: item)/2)
                            })
                        }
                    }
                    .padding(.bottom, 3)
                }
            }
        }
    }

    func didTap(button: CalcButton) {
        switch button {
        case .add, .subtract, .mutliply, .divide, .equal:
            if button == .add {
                self.currentOperation = .add
                self.runningNumber = Int(self.value) ?? 0
                self.value = "\(runningNumber + Int(self.value) ?? 0)"
                
            }
            else if button == .subtract {
                self.currentOperation = .subtract
                self.runningNumber = Int(self.value) ?? 0
            }
            else if button == .mutliply {
                self.currentOperation = .multiply
                self.runningNumber = Int(self.value) ?? 0
            }
            else if button == .divide {
                self.currentOperation = .divide
                self.runningNumber = Int(self.value) ?? 0
            }
            else if button == .equal {
                let runningValue = self.runningNumber
                let currentValue = Int(self.value) ?? 0
                switch self.currentOperation {
                case .add: self.value = "\(runningValue + currentValue)"
                case .subtract: self.value = "\(runningValue - currentValue)"
                case .multiply: self.value = "\(runningValue * currentValue)"
                case .divide: self.value = "\(runningValue / currentValue)"
                case .none:
                    break
                }
            }

            if button != .equal {
                self.value = "0"
            }
        case .clear:
            self.value = "0"
        case .decimal, .negative, .percent:
            break
        default:
            let number = button.rawValue
            if self.value == "0" {
                value = number
            }
            else {
                self.value = "\(self.value)\(number)"
            }
        }
    }

    func buttonWidth(item: CalcButton) -> CGFloat {
        if item == .zero {
            return ((UIScreen.main.bounds.width - (4*12)) / 4) * 2
        }
        return (UIScreen.main.bounds.width - (5*12)) / 4
    }

    func buttonHeight() -> CGFloat {
        return (UIScreen.main.bounds.width - (5*12)) / 4
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

这比预期的要棘手。当您按下一个运算符(+、-、* 等)时,常规计算器也会显示部分结果 – 不仅在“=”上。 所以每次点击运算符,你都必须计算partialResult。

我不得不引入一个新的变量 AwaitingNewNumberInput 来处理这种情况,您看到的是部分结果,但是当按下一个数字时,您开始输入一个新的数字。

对不起,但为了更清楚(至少对我自己而言),我还重命名了变量。我将所有计算变量都保留为 Int 以减少从 String 的转换。

struct ContentView: View {
    
    @State var displayNumber = 0 // change to Int
    @State var lastResult = 0
    @State var currentOperation: Operation = .none
    @State var awaitingNewNumberInput = true // to switch from result display to input

    let buttons: [[CalcButton]] = [
        [.clear, .negative, .percent, .divide],
        [.seven, .eight, .nine, .mutliply],
        [.four, .five, .six, .subtract],
        [.one, .two, .three, .add],
        [.zero, .decimal, .equal],
    ]
    
    var body: some View {
        ZStack {
            Color.black.edgesIgnoringSafeArea(.all)
            
            VStack {
                Spacer()
                
                // Text display
                HStack {
                    Spacer()
                    Text("\(displayNumber)") // show value as string
                        .font(.system(size: 100))
                        .foregroundColor(.white)
                }
                .padding()
                
                // Our buttons
                ForEach(buttons, id: \.self) { row in
                    HStack(spacing: 12) {
                        ForEach(row, id: \.self) { item in
                            Button(action: {
                                didTap(button: item)
                            }, label: {
                                Text(item.rawValue)
                                    .font(.system(size: 32))
                                    .frame(
                                        width: buttonWidth(item: item),
                                        height: buttonHeight()
                                    )
                                    .background(item.buttonColor)
                                    .foregroundColor(.white)
                                    .cornerRadius(buttonWidth(item: item)/2)
                            })
                        }
                    }
                    .padding(.bottom, 3)
                }
            }
        }
    }
    
    func didTap(button: CalcButton) {
        
        
        switch button {
        case .add:
            setCurrentResult()
            currentOperation = .add
            awaitingNewNumberInput = true

        case .subtract:
            setCurrentResult()
            currentOperation = .subtract
            awaitingNewNumberInput = true

        case .mutliply:
            setCurrentResult()
           currentOperation = .multiply
            awaitingNewNumberInput = true

        case .divide:
            setCurrentResult()
            currentOperation = .divide
            awaitingNewNumberInput = true

        case .equal:
            setCurrentResult()
            currentOperation = .none
            awaitingNewNumberInput = true

        case .clear:
            // set ALL to 0
            displayNumber = 0
            lastResult = 0
            currentOperation = .none
            awaitingNewNumberInput = true

        case .decimal, .negative, .percent:
            break
            
        default:
            // number input
            let number = Int(button.rawValue) ?? 0 // string to Int
            if awaitingNewNumberInput {
                awaitingNewNumberInput = false
                displayNumber = number
            } else {
                displayNumber = displayNumber * 10 + number
            }
        }
    }
    
    
    // check if an older operation is active, calculate partial result
    func setCurrentResult() {
        switch currentOperation {
        case .add:
            displayNumber += lastResult
        case .subtract:
            displayNumber = lastResult - displayNumber
        case .multiply:
            displayNumber *= lastResult
        case .divide:
            displayNumber = lastResult / displayNumber
        case .none:
            break
        }
        lastResult = displayNumber
        currentOperation = .none
    }
    
    
    func buttonWidth(item: CalcButton) -> CGFloat {
        if item == .zero {
            return ((UIScreen.main.bounds.width - (4*12)) / 4) * 2
        }
        return (UIScreen.main.bounds.width - (5*12)) / 4
    }
    
    func buttonHeight() -> CGFloat {
        return (UIScreen.main.bounds.width - (5*12)) / 4
    }
}