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

Taro
  • 23
  • 5
  • 1
    [This answer](https://stackoverflow.com/a/66735835/9223839) implements a custom formatter for something similar, it could be worthwhile to explore. – Joakim Danielson Mar 07 '23 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`. – malhal Mar 07 '23 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. – Hongtron Mar 08 '23 at 03:04

2 Answers2

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
        }
    }
Jonas Lang
  • 213
  • 1
  • 2
  • 12
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
    }
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848