Challenged shouldChangeCharactersIn behaviour.

Hey, writing again due to difficulties in completing this example.

Despite the bad user experience, I want the text to be formatted dynamically as I type, rather than at the end and make space after every 2 letters.

Everything works fine until we want to edit a string within our TextField. I want to perform these operations on a limited text, a maximum of 13 characters, so I think it's possible to do but still have some issues with text editing.

Has anyone done something similar or has an idea on how to fix this?

struct CustomTextFieldView: UIViewRepresentable {
    @Binding var text: String
    
    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField()
        textField.delegate = context.coordinator
        textField.text = text
        textField.placeholder = "Enter text here"
        return textField
    }
    
    func updateUIView(_ uiView: UITextField, context: Context) {
        
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(text: $text)
    }
    
    class Coordinator: NSObject, UITextFieldDelegate {
        @Binding var text: String
        
        init(text: Binding<String>) {
            self._text = text
        }
        
        func textField(_ textField: UITextField,
                       shouldChangeCharactersIn range: NSRange,
                       replacementString string: String) -> Bool {
            // Get the current text in the textField
            guard let currentText = textField.text,
                  let textRange = Range(range, in: currentText) else {
                return true
            }

            // Construct the new text after replacement
            let newText = currentText.replacingCharacters(in: textRange, with: string)
            
            // Disallow input if the total character count exceeds 13 or contains a space
            if !string.isEmpty {
                if newText.count > 13 || string.contains(" "){
                    return false
                }

                // Insert a space after every 2 characters
                if newText.count % 3 == 0 {
                    
                    let insertionIndex = newText.index(newText.startIndex, offsetBy: newText.count - 1)
                    textField.text?.insert(" ", at: insertionIndex)
                }
            }

            return true
        }
    }
    
}


struct ContentView: View {
    @State var text = ""
    var body: some View {
        VStack {
            CustomTextFieldView(text: $text)
        }
    }
}

It adds a lot of complexity to the editing process. Our code works as expected if a user backspaces at the end of the text, but deletes the wrong character if they move the cursor. Something that I found helpful was to not add injected characters after user typed text, other than possibly at the end. Essentially reformatting the text after the edit.

Thanks right now im a little bit closer but still there is issue when I try to delete more than 2 character and I got more than expected 2 letters close together. For example when I got text AB CD EF G and I try delete C the best thing for me would be AB DE FG without changing the cursor position. (I know my code looks terrible but I run out of ideas)

func textField(_ textField: UITextField,
               shouldChangeCharactersIn range: NSRange,
               replacementString string: String) -> Bool {
    
    guard let currentText = textField.text,
          let textRange = Range(range, in: currentText) else {
        return true
    }

    let newText = currentText.replacingCharacters(in: textRange, with: string)
    // if there is more than 4 spaces means we cant add extra " "
    let whiteSpacesCount = newText.filter(\.isWhitespace).count
    
    if newText.count > 13 {
        return false
    }
    
    if !string.isEmpty {
        
        if newText.count % 3 == 0 && whiteSpacesCount < 4 {
            
            let insertionIndex = newText.index(newText.startIndex, offsetBy: newText.count - 1)
            textField.text?.insert(" ", at: insertionIndex)
        }
    }
    return true
}
Challenged shouldChangeCharactersIn behaviour.
 
 
Q