Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI Textfield Trigger Commit Manually iOS

Tags:

ios

swiftui

The issue I have is that the decimalFormatter will not trigger and update the binding unless the textField gets a commit event triggered, i.e. return is tapped.

Thus, I'm looking for how do you manually trigger the textfields commit event?

The formatter code below will take any number and ensure it always has one decimal place (I.E -- 10.5) and also reverts the input back to the previous valid input if letter characters were inserted which is exactly what I want.

import SwiftUI
import Combine

struct StandardRegimen: View {
    @State private var totalDose = 6000.0

    private var decimalFormatter: NumberFormatter = {
        let f = NumberFormatter()
        f.isLenient = true
        f.numberStyle = .none
        f.maximumFractionDigits = 1
        f.minimumFractionDigits = 1
        f.alwaysShowsDecimalSeparator = true
        return f
    }()

    var body: some View{
       return
       VStack(alignment:.center,spacing:10){
            TextField("?", value:$totalDose, formatter: self.decimalFormatter, onCommit: {
               print("COMMITED!");
            }).font(.system(size: 25.0))
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .keyboardType(.decimalPad)
       }
    }

If you remove the modifier code .keyboardType(.decimalPad) and press the return key on the keyboard it will trigger the COMMITED message and close the keyboard

However, if you leave the decimal pad modifier on then there is no way to trigger the commit because the decimal pad does not have a return key.

I wrote an answer here on how to get the keyboard to go away by tapping in the open space area (How to hide keyboard when using SwiftUI?)

I have looked into other solutions using binding to a string and using the textfields text initializer parameter instead of value since this will work correctly with a bound value, but this updates on every keystroke for some very wonky results (I.E -- it's difficult for the user to type and edit mistakes) when I'm looking for it to run the formatter only just after commit, which I want to occur when the user taps to dismiss the keyboard since I will not have the return key option on the decimal keypad.

Any help is appreciated on solutions to this issue.

like image 330
Joseph Astrahan Avatar asked Dec 19 '19 23:12

Joseph Astrahan


Video Answer


1 Answers

This may be a little late, but I have come up with a workaround for using other keyboard types with a TextField: I use the onEditingChanged event instead of the onCommit event and check the Bool value passed into the method. If the value is false, it replicates the behavior of the onCommit method. Here is your code but formatted to use my method:

import SwiftUI
import Combine

struct StandardRegimen: View {
    @State private var totalDose = 6000.0

    private var decimalFormatter: NumberFormatter = {
        let f = NumberFormatter()
        f.isLenient = true
        f.numberStyle = .none
        f.maximumFractionDigits = 1
        f.minimumFractionDigits = 1
        f.alwaysShowsDecimalSeparator = true
        return f
    }()

    var body: some View{
       VStack(alignment:.center,spacing:10){
            TextField("?", value:$totalDose, formatter: self.decimalFormatter, onEditingChanged: { edit in
                // Editing has finished
                if !edit {
                    print("COMMITED!");
                }
            }).font(.system(size: 25.0))
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .keyboardType(.decimalPad)
       }
    }
}

This solution should work for all keyboard types (I have only tested regular and num pad).

like image 139
ImTheSquid Avatar answered Nov 08 '22 11:11

ImTheSquid