From 691c3eaa5331c4d3678d7ce449e6eef325d6fc7e Mon Sep 17 00:00:00 2001 From: Andrea Antonioni Date: Sun, 6 Aug 2017 00:04:29 +0200 Subject: [PATCH] Implement InputTextView with support to a placeholder --- MessageKit.xcodeproj/project.pbxproj | 4 + Sources/InputTextView.swift | 109 +++++++++++++++++++++++++++ Sources/MessageInputBar.swift | 8 +- 3 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 Sources/InputTextView.swift diff --git a/MessageKit.xcodeproj/project.pbxproj b/MessageKit.xcodeproj/project.pbxproj index 5fd8f5d0..e7586836 100644 --- a/MessageKit.xcodeproj/project.pbxproj +++ b/MessageKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 171D5AB91F36712B0053DF69 /* InputTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171D5AB81F36712B0053DF69 /* InputTextView.swift */; }; 882D75841DE507320033F95F /* MessagesDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 882D75831DE507320033F95F /* MessagesDataSource.swift */; }; 888CEBFC1D3FD525005178DE /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 888CEBFB1D3FD525005178DE /* MessagesViewController.swift */; }; 88916B2D1CF0DF2F00469F91 /* MessageKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88916B221CF0DF2F00469F91 /* MessageKit.framework */; }; @@ -43,6 +44,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 171D5AB81F36712B0053DF69 /* InputTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputTextView.swift; sourceTree = ""; }; 882D75831DE507320033F95F /* MessagesDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesDataSource.swift; sourceTree = ""; }; 888CEBFB1D3FD525005178DE /* MessagesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesViewController.swift; sourceTree = ""; }; 88916B221CF0DF2F00469F91 /* MessageKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MessageKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -157,6 +159,7 @@ B0655A2D1F23D8BC00542A83 /* MessagesCollectionView.swift */, B0655A4C1F244C0600542A83 /* MessageCollectionViewCell.swift */, B0655A371F23EE8B00542A83 /* MessageInputBar.swift */, + 171D5AB81F36712B0053DF69 /* InputTextView.swift */, B074EE921F35587100ABB8C8 /* MessageHeaderView.swift */, B074EE941F35588A00ABB8C8 /* MessageFooterView.swift */, ); @@ -328,6 +331,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 171D5AB91F36712B0053DF69 /* InputTextView.swift in Sources */, B074EE971F355FBC00ABB8C8 /* MessagesLayoutDelegate.swift in Sources */, 882D75841DE507320033F95F /* MessagesDataSource.swift in Sources */, 888CEBFC1D3FD525005178DE /* MessagesViewController.swift in Sources */, diff --git a/Sources/InputTextView.swift b/Sources/InputTextView.swift new file mode 100644 index 00000000..d36d34bb --- /dev/null +++ b/Sources/InputTextView.swift @@ -0,0 +1,109 @@ +/* + MIT License + + Copyright (c) 2017 MessageKit + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +import UIKit + +open class InputTextView: UITextView { + + // MARK: - Properties + + open var placeholder: NSString? { + didSet { + guard placeholder != oldValue else { return } + setNeedsDisplay() + } + } + + open var placeholderTextColor: UIColor = .lightGray { + didSet { + guard placeholderTextColor != oldValue else { return } + setNeedsDisplay() + } + } + + open var placeholderInsets: UIEdgeInsets = UIEdgeInsets(top: 7, + left: 5, + bottom: 7, + right: 5) { + didSet { + guard placeholderInsets != oldValue else { return } + setNeedsDisplay() + } + } + + // MARK: - Initializers + + override public init(frame: CGRect, textContainer: NSTextContainer?) { + super.init(frame: frame, textContainer: textContainer) + commonInit() + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + commonInit() + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + // MARK: - Methods + + override open func draw(_ rect: CGRect) { + super.draw(rect) + + guard text.isEmpty, let placeholder = placeholder else { return } + + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.alignment = textAlignment + + var attributes: [String: Any] = [ + NSForegroundColorAttributeName: placeholderTextColor, + NSParagraphStyleAttributeName: paragraphStyle + ] + if let font = font { + attributes[NSFontAttributeName] = font + } + + placeholder.draw(in: UIEdgeInsetsInsetRect(rect, placeholderInsets), + withAttributes: attributes) + + } + + fileprivate func commonInit() { + NotificationCenter.default.addObserver(self, + selector: #selector(textDidChange), + name: NSNotification.Name.UITextViewTextDidChange, + object: self) + } + + func textDidChange(notification: Notification) { + guard let notificationObject = notification.object as? InputTextView, + notificationObject === self else { return } + + setNeedsDisplay() + + } + +} diff --git a/Sources/MessageInputBar.swift b/Sources/MessageInputBar.swift index 6ff4889e..cc251ab6 100644 --- a/Sources/MessageInputBar.swift +++ b/Sources/MessageInputBar.swift @@ -30,10 +30,10 @@ open class MessageInputBar: UIView, UITextViewDelegate { open let inputTextView: UITextView = { - let inputTextView = UITextView(frame: .zero) + let inputTextView = InputTextView(frame: .zero) inputTextView.font = UIFont.preferredFont(forTextStyle: .body) - inputTextView.text = "New Message" - inputTextView.textColor = .lightGray + inputTextView.textColor = .black + inputTextView.placeholder = "New Message" inputTextView.backgroundColor = .white inputTextView.layer.borderColor = UIColor.lightGray.cgColor inputTextView.layer.borderWidth = 1.0 @@ -97,7 +97,7 @@ open class MessageInputBar: UIView, UITextViewDelegate { public func textViewDidChange(_ textView: UITextView) { let trimmedText = textView.text.trimmingCharacters(in: .whitespacesAndNewlines) - sendButton.isEnabled = !trimmedText.isEmpty && textView.text != "New Message" + sendButton.isEnabled = !trimmedText.isEmpty invalidateIntrinsicContentSize() }