简体   繁体   中英

Changing A Picker to a TextField in SwiftUI

I'm a newbie self teaching myself iOS development (100DaysOfSwiftUI by Paul Hudson, Project 1), and currently I came across a problem that I haven't been able to solve yet. Originally, the numberOfPeople section had a picker with below code, which I'm trying to change to a text field. Started by changing its @State property (@State private var numberOfPeople = 2) from 2 to empty string, and tried creating another computed property for people count. when the number of people text field is left empty, 0 doesn't appear as default on the simulator on the amount per person section when I run the project, instead NaN appears as in the screenshot below. (Which makes me wonder if numberOfPeople converted successfully to an Integer through nil coalescing as below). Only time the project functions as it should is when I enter a value in the number of people text field. I'm not 100% sure where I went wrong with this, but any help will be greatly appreciated!!

struct ContentView: View {
    @State private var checkAmount = ""
    @State private var numberOfPeople = ""
    @State private var tipPercentage = 2
    
    let tipPercentages = [10,15,20,25,0]
    let allPeople = 2...100

    var totalPerPerson: Double {
        let peopleCount = Double(numberOfPeople) ?? 0
        let tipSelection = Double(tipPercentages[tipPercentage])
        let orderAmount = Double(checkAmount) ?? 0
        
        let tipValue = orderAmount / 100 * tipSelection
        let grandTotal = orderAmount + tipValue
        let amountPerPerson = grandTotal / peopleCount

        return amountPerPerson
    }
    
    var grandTotal: Double {
        let tipSelection = Double(tipPercentages[tipPercentage])
        let orderAmount = Double(checkAmount) ?? 0
        
        let tipValue = orderAmount / 100 * tipSelection
        let totalAmount = orderAmount + tipValue
        
        return totalAmount
    }
    
    var body: some View {
        NavigationView {
            Form {
                Section {
                    TextField("Amount", text: $checkAmount)
                        .keyboardType(.decimalPad)
                    
                    TextField("Number of people", text: $numberOfPeople)
                        .keyboardType(.numberPad)
                }
                
                Section(header: Text("How much tip do you want to leave?")) {
                    Picker("Tip percentage", selection: $tipPercentage) {
                        ForEach(0 ..< tipPercentages.count) {
                            Text("\(self.tipPercentages[$0])%")
                        }
                    }
                    .pickerStyle(SegmentedPickerStyle())
                }
                
                Section (header: Text("Total Amount")){
                    Text("$\(grandTotal, specifier: "%.2f")")
                }
                
                Section (header: Text("Amount Per Person")){
                    Text("$\(totalPerPerson, specifier: "%.2f")")
                }
            }
            .navigationBarTitle("WeSplit")
        }
    }
}

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

(Original code for picker)
Picker("Number of people", selection: $numberOfPeople) {
        ForEach(2 ..< 100) {
            Text("\($0) people")

(Original code for people count)
let peopleCount = Double(numberOfPeople + 2)

project simulator

What you're seeing is a result of trying to divide by zero. You can avoid that calculation by returning 0 from your totalPerPerson function if peopleCount is 0 before doing the division using something like this:

var totalPerPerson: Double {
    let peopleCount = Double(numberOfPeople) ?? 0
    let tipSelection = Double(tipPercentages[tipPercentage])
    let orderAmount = Double(checkAmount) ?? 0
    
    guard peopleCount > 0 else {
        return 0
    }
    
    let tipValue = orderAmount / 100 * tipSelection
    let grandTotal = orderAmount + tipValue
    let amountPerPerson = grandTotal / peopleCount

    return amountPerPerson
}

Keep in mind that with your new TextField , as opposed to the picker, even if you specify .decimalPad or .numberPad , there are still ways for the user to enter non-numerical values in those fields, so you'd probably want to put up an error if that happens (or, search here on SO for solutions about fields that only accept numbers). An example for such a TextField is specified in this solution

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM