100 Days of SwiftUI Day 17

100 Days of SwiftUI – Day 17 – WeSplit

We’ve arrived at day 17 of the 100 Days of SwiftUI! Yesterday, we were introduced to the very first project we’re going to make using SwiftUI. Today, we actually went ahead and made it! No time to wait, it’s time to dive in.

Reading text from the TextField in SwiftUI

Let’s start off with an essential part of this app: getting input from a user and using that input to calculate other data.

SwiftUI features a TextField that creates a text field with a label and a binding value. In this case, the goal is to let a user enter the total cost for a meal. That total amount is saved in a State variable so that the view is updated every time a new value is entered.

struct ContentView: View {
    @State private var checkAmount = 0.0
    @State private var numberOfPeople = 2
    @State private var tipPercentage = 20
    @FocusState private var amountIsFocused: Bool
    
    let tipPercentages = [10, 15, 20, 25, 0]
    
    var totalPerPerson: Double {
        // Calculate total per person
        let peopleCount = Double (numberOfPeople + 2)
        let tipSelection = Double (tipPercentage)
        
        let tipValue = checkAmount / 100 * tipSelection
        let grandTotal = checkAmount + tipValue
        let amountPerPerson = grandTotal / peopleCount
        
        return amountPerPerson
    }
    
    var body: some View {
        NavigationView {
            Form {
                Section {
                    TextField("Amount", value: $checkAmount, format:
                            .currency(code: Locale.current.currencyCode ?? "USD"))
                            .keyboardType(.decimalPad)
                            .focused($amountIsFocused)

This code sample is exactly as used in our project. I’ll post the complete code at the end of this post.

Creating pickers in a form in SwiftUI

Next up after the TextField are the Pickers. Pickers serve multiple purposes and how they look depends on the context of your app and which device it is running on. For our particular app, it will be used two times: once to pick how many people we have to split the bill with and what percentage the tip is.

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

Picker("Tip percentage", selection: $tipPercentage) {
                        ForEach(tipPercentages, id: \.self) {
                            Text($0, format: .percent)
                        }
                    }

SwiftUI will automatically try to determine what the best style is for our picker. However, we can also manually choose which style we want to use.

.pickerStyle(.segmented)

Hiding the keyboard in SwiftUI

After a user has entered some input, we want them to be able to close the keyboard. It shouldn’t be up indefinitely, right?

In the first code example of this post, you’ll see the variable amountIsFocused. This Bool is used to set a TextField in focus. When a Textfield is in focus, SwiftUI is silently aware of this and knows that that specific field is where the input should be placed.

Next up, we add a toolbar that displays whenever the keyboard appears. By adding a button to the toolbar that puts the amountIsFocused variable to false when pressed, our users can close the keyboard.

.toolbar{
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    
                    Button("Done") {
                        amountIsFocused = false
                    }
                }
            }

The complete project

Down below you’ll find the full code for the WeSplit project, as well as a few screenshots of the app in action.

import SwiftUI

struct ContentView: View {
    @State private var checkAmount = 0.0
    @State private var numberOfPeople = 2
    @State private var tipPercentage = 20
    @FocusState private var amountIsFocused: Bool
    
    let tipPercentages = [10, 15, 20, 25, 0]
    
    var totalPerPerson: Double {
        // Calculate total per person
        let peopleCount = Double (numberOfPeople + 2)
        let tipSelection = Double (tipPercentage)
        
        let tipValue = checkAmount / 100 * tipSelection
        let grandTotal = checkAmount + tipValue
        let amountPerPerson = grandTotal / peopleCount
        
        return amountPerPerson
    }
    
    var body: some View {
        NavigationView {
            Form {
                Section {
                    TextField("Amount", value: $checkAmount, format:
                            .currency(code: Locale.current.currencyCode ?? "USD"))
                            .keyboardType(.decimalPad)
                            .focused($amountIsFocused)
                    
                    Picker("Number of people", selection: $numberOfPeople) {
                        ForEach(2..<100) {
                            Text("\($0) people")
                        }
                    }
                }
                
                Section {
                    Picker("Tip percentage", selection: $tipPercentage) {
                        ForEach(tipPercentages, id: \.self) {
                            Text($0, format: .percent)
                        }
                    }
                    
                    .pickerStyle(.segmented)
                } header: {
                    Text("Tip percentage")
                }
                
                Section {
                    Text(totalPerPerson, format: .currency(code: Locale.current.currencyCode ?? "USD"))
                }
            }
            
            .navigationTitle("WeSplit")
            .toolbar{
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    
                    Button("Done") {
                        amountIsFocused = false
                    }
                }
            }
        }
    }
}

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

And that’s it for day 17! While the project is finished as is, we’re not quite done with it yet! Tomorrow we’ll be reviewing all we learned, which is an important step in making sure everything really sinks in. Time to march on!

Darryl

Hi! My name is Darryl and this is my personal blog where I write about my journey as I learn programming! You'll also find articles about other things that interest me including games, tech and anime.

Post navigation

Leave a Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

100 Days of SwiftUI – Day 48

100 Days of SwiftUI – Day 34

100 Days of SwiftUI – Day 84

100 Days of SwiftUI – Day 69