I have a UITextView in a ViewController. I've implemented shouldChangeTextInRange delegate method from UITextViewDelegate. The range value I obtain through the above delegate method for deleting a single character is something like {location, 1}.
But if I use the slide-to-type mechanism to insert a word before performing delete operation, the entire word gets deleted instead of a single character. I need to keep track of this.
For example, I insert "Hello" using the slide-to-type mechanism. If I press delete key in the keyboard, I get {4, 1} as range but the entire word "Hello" has been deleted in text view. In this case, I need the range to be {0, 5} much like selecting the text "Hello" and deleting it.
Is there a way to differentiate between normal delete operation and slide-to-type delete operation? How can I get the actual range that has been deleted in the text view?
A little help is very much appreciated.
This is what I've tried.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.addTextView()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
}
extension ViewController {
func addTextView() {
let textContainer = NSTextContainer(size: CGSize(width: 200, height: CGFloat.greatestFiniteMagnitude))
let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainer)
let textStorage = NSTextStorage()
textStorage.delegate = self
textStorage.addLayoutManager(layoutManager)
let textViewFrame = CGRect(x: 50, y: 50, width: 200, height: 200)
let textView = UITextView(frame: textViewFrame, textContainer: textContainer)
textView.backgroundColor = .green
textView.delegate = self
self.view.addSubview(textView)
}
}
extension ViewController: UITextViewDelegate {
func textViewDidBeginEditing(_ textView: UITextView) {
print("text editing began")
}
func textViewDidChange(_ textView: UITextView) {
print("text view content changed")
}
func textViewDidChangeSelection(_ textView: UITextView) {
print("text view selection changed")
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
print("should change \(text) in \(range)")
return true
}
func textViewDidEndEditing(_ textView: UITextView) {
print("text editing ended")
}
}
extension ViewController: NSTextStorageDelegate {
func textStorage(_ textStorage: NSTextStorage, willProcessEditing editedMask: NSTextStorage.EditActions, range editedRange: NSRange, changeInLength delta: Int) {
print("will process \(editedRange)")
}
func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorage.EditActions, range editedRange: NSRange, changeInLength delta: Int) {
print("did process \(editedRange)")
}
}
EDIT 1:
I have a separate storage mechanism on which I update the changes made to the text view based on the range and replacement text provided in shouldChangeText delegate method. I haven't included that for the sake of simplicity.