Search code examples
swiftswiftui

How to highlight default value in TextField when user selects the field? Or omit value to show title?


I am new to swift but not new to programming but I have little experience with UI work.

I'm creating my first simple app that converts temperatures from celsius to Fahrenheit and vice versa.

When the user taps on the text field to enter their temperature, they have to manually delete the default value 0. However, it would be better if, when the user taps the textfield either a) the default text is highlighted so whatever they type automatically overwrites the default value or b) the default value disappears completely to show the word "temperature" until the user types in their value.

Is there a simple way to do this?

This is the code I have and a picture of what is currently happening.

import SwiftUI

struct ContentView: View {
    @State private var temp: Int = 0
    @State private var tempUnit: String = ""
    @State private var tempConvertUnit: String = ""

    var convertedTemp: Int {
        switch(tempUnit){
        case "F":
            if tempConvertUnit == "C"{
                return Int((temp - 32) * 5 / 9)
            }
            else {
                return temp
            }
                    
        case "C":
            if tempConvertUnit == "F"{
                return Int(temp * 9/5 + 32)
            }
            else {
                return temp
            }
        default:
            return 0
        }

        
    }
 
    let tempUnits = ["F", "C"]
    
    @FocusState private var amountIsFocused: Bool

    
    var body: some View {
        NavigationStack{
            Form{
                Section("Temperature"){
               
                    TextField("Temperatue", value: $temp, format: .number)
                        .keyboardType(.decimalPad)
                        .focused($amountIsFocused)
                 
                    Picker("Unit", selection: $tempUnit){
                        ForEach(tempUnits, id: \.self){
                            unit in Text(unit)
                        }
                    }.pickerStyle(.segmented)
                }
                Section("Converted Temperature"){
  
                    Text(convertedTemp, format: .number)
                  
                 
                    Picker("Unit", selection: $tempConvertUnit){
                        ForEach(tempUnits, id: \.self){
                            unit in Text(unit)
                        }
                    }.pickerStyle(.segmented)
                }
                
                
            }.navigationTitle("Converter")
                .toolbar {
                    if amountIsFocused{
                        Button("Done"){
                            amountIsFocused = false
                        }
                    }
                }
        }
    }
}

enter image description here


Solution

  • What you can do is change the type of the variable used in the binding for the TextField to an optional Int. Then:

    • change the implementation of the computed property convertedTemp to work with the optional
    • when focus is gained, set the value to nil
    • when focus is lost, you could set the value back to 0 if it is still nil
    • to show "Temperature" after the value has been reset, supply a prompt to the TextField initializer.

    You might like to consider using ternary operators in convertedTemp too:

    @State private var temp: Int? = 0
    
    var convertedTemp: Int {
        if let temp {
            switch(tempUnit) {
            case "F":
                tempConvertUnit == "C" ? Int((temp - 32) * 5 / 9) : temp
            case "C":
                tempConvertUnit == "F" ? Int(temp * 9/5 + 32) : temp
            default:
                0
            }
        } else {
            0
        }
    }
    
    TextField(
        "Temperatue",
        value: $temp,
        format: .number,
        prompt: Text("Temperature")
    )
    .keyboardType(.decimalPad)
    .focused($amountIsFocused)
    .onChange(of: amountIsFocused) { oldVal, newVal in
        if newVal {
            temp = nil
        } else if temp == nil {
            temp = 0
        }
    }
    

    Animation