From f23c1b09076dad9781daf870a8a4d8a6d87c140f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktoras=20Laukevic=CC=8Cius?= Date: Mon, 2 Apr 2018 20:37:00 +0300 Subject: [PATCH 1/2] Text input customization point allowing to ignore typed text --- .../MessageAutocompleteController.swift | 3 ++- MessageViewController/MessageTextView.swift | 11 ++++++++--- MessageViewController/MessageView.swift | 4 +++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/MessageViewController/MessageAutocompleteController.swift b/MessageViewController/MessageAutocompleteController.swift index 806eb38..9367014 100644 --- a/MessageViewController/MessageAutocompleteController.swift +++ b/MessageViewController/MessageAutocompleteController.swift @@ -233,7 +233,7 @@ public final class MessageAutocompleteController: MessageTextViewListener { preserveTypingAttributes(for: textView) } - public func willChangeRange(textView: MessageTextView, to range: NSRange) { + public func willChangeText(textView: MessageTextView, inRange range: NSRange, to: String) -> Bool { // range.length == 1: Remove single character // range.lowerBound < textView.selectedRange.lowerBound: Ignore trying to delete @@ -261,6 +261,7 @@ public final class MessageAutocompleteController: MessageTextViewListener { }) } } + return true } } diff --git a/MessageViewController/MessageTextView.swift b/MessageViewController/MessageTextView.swift index 3399d65..82c9dae 100644 --- a/MessageViewController/MessageTextView.swift +++ b/MessageViewController/MessageTextView.swift @@ -10,7 +10,7 @@ import UIKit public protocol MessageTextViewListener: class { func didChange(textView: MessageTextView) func didChangeSelection(textView: MessageTextView) - func willChangeRange(textView: MessageTextView, to range: NSRange) + func willChangeText(textView: MessageTextView, inRange: NSRange, to: String) -> Bool } open class MessageTextView: UITextView, UITextViewDelegate { @@ -134,8 +134,13 @@ open class MessageTextView: UITextView, UITextViewDelegate { } public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { - enumerateListeners { $0.willChangeRange(textView: self, to: range) } - return true + // If listener changes text then subsequent listeners will probably get incorrect affected range + // and text as they were changed by previous listener. So be careful playing with textView + var shouldChange = true + // if at least one listener changes text and needs to ignore typed text then this method returns + // that just typed text needs to be ignored + enumerateListeners { shouldChange = shouldChange && $0.willChangeText(textView: self, inRange: range, to: text) } + return shouldChange } } diff --git a/MessageViewController/MessageView.swift b/MessageViewController/MessageView.swift index b01beb5..f6434d4 100644 --- a/MessageViewController/MessageView.swift +++ b/MessageViewController/MessageView.swift @@ -336,6 +336,8 @@ public final class MessageView: UIView, MessageTextViewListener { delegate?.selectionDidChange(messageView: self) } - public func willChangeRange(textView: MessageTextView, to range: NSRange) {} + public func willChangeText(textView: MessageTextView, inRange: NSRange, to: String) -> Bool { + return true + } } From 7e391984d0ae869a94183c44c4094e54c2b18f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktoras=20Laukevic=CC=8Cius?= Date: Mon, 2 Apr 2018 20:38:52 +0300 Subject: [PATCH 2/2] After autocompleted text is removed preceding character is not removed --- MessageViewController/MessageAutocompleteController.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MessageViewController/MessageAutocompleteController.swift b/MessageViewController/MessageAutocompleteController.swift index 9367014..e535e46 100644 --- a/MessageViewController/MessageAutocompleteController.swift +++ b/MessageViewController/MessageAutocompleteController.swift @@ -248,6 +248,7 @@ public final class MessageAutocompleteController: MessageTextViewListener { if let isAutocomplete = attribute[NSAttributedAutocompleteKey] as? Bool, isAutocomplete { // Remove the autocompleted substring let lowerRange = NSRange(location: 0, length: range.location + 1) + var shouldPreserveTypedText = true textView.attributedText.enumerateAttribute(NSAttributedAutocompleteKey, in: lowerRange, options: .reverse, using: { (_, range, stop) in // Only delete the first found range @@ -258,7 +259,9 @@ public final class MessageAutocompleteController: MessageTextViewListener { textView.selectedRange = NSRange(location: range.location, length: 0) self.textView.textViewDidChange(textView) self.preserveTypingAttributes(for: textView) + shouldPreserveTypedText = false }) + return shouldPreserveTypedText } } return true