0

I want to add hyphen after 3rd character. I want to change like this. If I input 1111111 in textfield, it automatically change to 111-1111

@State var postalCode = ""

TextField("PostalCode", text: $postalCode)
             .onReceive(Just(postalCode)) { _ in
                 if postalCode.count > 8 {
                       postalCode = String(postalCode.prefix(8))
                  }
                  else if postalCode.count == 3{
                       postalCode = postalCode + "-"
                  }
               }

But this above code doesn't work when I delete the previous characters. I mean if I find wrong number, I can't go back before 3rd character. The textfield sticks to 111-. I could not manipulate it.

And I found a swift storyboard sample code.

class CreateViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var deckCodeLabel: UITextField!
 
    
     override func viewDidLoad() {
       super.viewDidLoad()
       deckCodeLabel.delegate = self
   }
   
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
       if (string == "") { return true }
       if (textField.text?.count == 3) {
           textField.text = (textField.text)! + string + "-"
           return false
       }

       textField.text = String(textField.text!.prefix(8))
       return true
   }

But I don't know how to change it to my code in SwiftUI

3
  • 1
    This answer implements a custom formatter for something similar, it could be worthwhile to explore. Commented Mar 7, 2023 at 13:49
  • Use .onChange but it might not fix your problem because text fields are buggy in SwiftUI so you might want to just wrap your UIKit implementation in UIViewRepresentable. Commented Mar 7, 2023 at 21:50
  • The func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) is from UITextFieldDelegate. To access this you need to create a UITextField view in UIKit and then use UIViewRepresentable to access in SwiftUI. I have used this a couple of times for complex text field validation but it ended up quite a lot of code for what it was. It did work well though. Look at UITextFieldDelegate for the functions you can access by going this route. Commented Mar 8, 2023 at 3:04

2 Answers 2

1

You can try this:

TextField("PostalCode", text: $postalCode)
    .onChange(of: postalCode) { _ in
        var withoutHyphen = String(postalCode.replacingOccurrences(of: "-", with: "").prefix(8))
        if withoutHyphen.count > 3 {
            withoutHyphen.insert("-", at: postalCode.index(postalCode.startIndex, offsetBy: 3))
            postalCode = withoutHyphen
        } else {
            postalCode = withoutHyphen
        }
    }
Sign up to request clarification or add additional context in comments.

Comments

0

One way to handle this is to insert the hyphen only if there are more than three digits, or if it’s already there in the correct place. So:

  • If the user types “123”, you leave it as “123”.
  • If the user types “1234”, you change it to “123-4”.
  • If the user types “123-“, you leave it as “123-“.
  • If the user types “123-“ and then backspace, the TextField removes the - and you leave it removed.
struct TestView: View {
    @State var postalCode = ""
    
    var body: some View {
        TextField("Postal Code", text: $postalCode)
            .onChange(of: postalCode) { _ in
                groomCode()
            }
    }
    
    private func groomCode() {
        var groomed = ""
        for c in postalCode {
            if c == "-" && groomed.count == 3 {
                // Copy over the hyphen that was in the correct place.
                groomed.append(c)
            } else if c.isASCII && c.isNumber {
                if groomed.count == 3 {
                    // Insert a hyphen before the 4th digit.
                    groomed.append("-")
                }
                // Copy over the digit.
                groomed.append(c)
            } 
            if groomed.count == 8 {
                break
            }
        }
        postalCode = groomed
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.