I am trying to apply NSAttributedString styles to a UITextField after processing a new text entry, keystroke by keystroke. The problem is that any time I replace the text the cursor will jump the very end on each change. Here's my current approach …
Receive and display text change immediately (same issue applies when I return false and do the text replacement manually)
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {
let range:NSRange = NSRange(location: range.location, length: range.length)
let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string);
return true
}
I subscribed to the UITextFieldTextDidChangeNotification notification. This triggers the styling. When the text is changed I replace it (NSString) with the formatted version (NSAttributedString) using some format() function.
func textFieldTextDidChangeNotification(userInfo:NSDictionary) {
var attributedString:NSMutableAttributedString = NSMutableAttributedString(string: fullString)
attributedString = format(textField.text) as NSMutableAttributedString
textField.attributedText = attributedString
}
Styling works fine like this. However after each text replacement the cursor jumps to the end of the string. How can I turn off this behaviour or manually move the cursor back where it started the edit? … or is there a better solution to style the text while editing?
This is a code working for swift 2. Enjoy it!
Note that last "if let" should always stay at the end of code.
To piggy back off an answer to a different question here: https://stackoverflow.com/a/51814368/431271, you shouldn't be modifying the text in
shouldChangeCharactersInRange
since that delegate method is intended only to let the field know whether or not to allow a change and isn't supposed to mutate.Instead, I like to handle the text change by subscribing to the value change, like this:
where the implementation of
sanitizeText
looks like this:Thanks @Stonz2 by the code in Objective-C. It works like a charm! I used it in my Swift project. The same code in Swift:
The way to make this work is to grab the location of the cursor, update the field contents, and then replace the cursor to its original position. I'm not sure of the exact equivalent in Swift, but the following is how I would do it in Obj-C.
To complement the other correct answers in this thread here are some code snippets for Swift 4.2 and for both UITextField and UITextView
UITextField
UITextView
This is an old question, but I had a similar issue and resolved it with the following Swift:
It works in the context of my app, hopefully it's useful for someone!