textview
This commit is contained in:
parent
daa37c5add
commit
174d26edc4
275
MVMCoreUI/BaseClasses/TextView.swift
Normal file
275
MVMCoreUI/BaseClasses/TextView.swift
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
//
|
||||||
|
// TextView.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 4/1/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
|
@objc protocol MFTextViewDelegate {
|
||||||
|
// Dismisses the keyboard.
|
||||||
|
@objc optional func dismissFieldInput(_ sender: Any?)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@objc open class TextView: UITextView, UITextViewDelegate {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open var model: MoleculeModelProtocol?
|
||||||
|
|
||||||
|
private var initialSetupPerformed = false
|
||||||
|
|
||||||
|
/// Set to true to hide the blinking textField cursor.
|
||||||
|
public var hideBlinkingCaret = false
|
||||||
|
|
||||||
|
public var hideBorder = true
|
||||||
|
|
||||||
|
public var borderPath: UIBezierPath?
|
||||||
|
|
||||||
|
public var errorShowing = false
|
||||||
|
|
||||||
|
weak var bottomLine: SeparatorView?
|
||||||
|
|
||||||
|
public var placeholderFont: UIFont = MFStyler.fontB3()! {
|
||||||
|
didSet {
|
||||||
|
if text.isEmpty {
|
||||||
|
font = placeholderFont
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var placeholder: String = "" {
|
||||||
|
didSet {
|
||||||
|
if text.isEmpty {
|
||||||
|
text = placeholder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var placeholderTextColor: UIColor = .mvmCoolGray3
|
||||||
|
|
||||||
|
public var displaysPlaceholder = false
|
||||||
|
|
||||||
|
private(set) var textStore: String = ""
|
||||||
|
|
||||||
|
public override var text: String! {
|
||||||
|
didSet {
|
||||||
|
if displaysPlaceholder && text.isEmpty {
|
||||||
|
text = placeholder
|
||||||
|
textColor = placeholderTextColor
|
||||||
|
} else {
|
||||||
|
textColor = .mvmBlack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private(set) var textFont: UIFont = MFStyler.fontB2()!
|
||||||
|
|
||||||
|
public override var font: UIFont? {
|
||||||
|
didSet {
|
||||||
|
if displaysPlaceholder && text.isEmpty {
|
||||||
|
font = placeholderFont
|
||||||
|
} else {
|
||||||
|
textColor = .mvmBlack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Delegate
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Holds a reference to the delegating class so this class can internally influence the TextField behavior as well.
|
||||||
|
public weak var didDeleteDelegate: TextFieldDidDeleteProtocol?
|
||||||
|
|
||||||
|
/// If you're using a MFViewController, you must set this to it
|
||||||
|
public weak var uiTextViewDelegate: UITextViewDelegate? {
|
||||||
|
get { return delegate }
|
||||||
|
set { delegate = newValue }
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraint
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public var heightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initialization
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public override init(frame: CGRect, textContainer: NSTextContainer?) {
|
||||||
|
super.init(frame: .zero, textContainer: nil)
|
||||||
|
initialSetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
public convenience init() {
|
||||||
|
self.init(frame: .zero, textContainer: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
public required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
initialSetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
convenience init(placeholderText: String, delegate: UITextViewDelegate?) {
|
||||||
|
self.init(frame: .zero, textContainer: nil)
|
||||||
|
self.delegate = delegate
|
||||||
|
displaysPlaceholder = true
|
||||||
|
self.placeholder = placeholderText
|
||||||
|
}
|
||||||
|
|
||||||
|
public func initialSetup() {
|
||||||
|
|
||||||
|
if !initialSetupPerformed {
|
||||||
|
tintColor = .black
|
||||||
|
initialSetupPerformed = true
|
||||||
|
setupView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func caretRect(for position: UITextPosition) -> CGRect {
|
||||||
|
|
||||||
|
if hideBlinkingCaret {
|
||||||
|
return .zero
|
||||||
|
}
|
||||||
|
|
||||||
|
let caretRect = super.caretRect(for: position)
|
||||||
|
return CGRect(origin: caretRect.origin, size: CGSize(width: 1, height: caretRect.height))
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func deleteBackward() {
|
||||||
|
super.deleteBackward()
|
||||||
|
didDeleteDelegate?.textFieldDidDelete()
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Drawing
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func draw(_ rect: CGRect) {
|
||||||
|
super.draw(rect)
|
||||||
|
|
||||||
|
borderPath?.removeAllPoints()
|
||||||
|
|
||||||
|
if !hideBorder {
|
||||||
|
layer.cornerRadius = 0
|
||||||
|
borderPath = UIBezierPath()
|
||||||
|
let width = frame.origin.x + frame.size.width
|
||||||
|
let height = frame.origin.y + frame.size.height
|
||||||
|
|
||||||
|
borderPath?.move(to: CGPoint(x: frame.origin.x, y: height))
|
||||||
|
borderPath?.addLine(to: CGPoint(x: frame.origin.x, y: frame.origin.y))
|
||||||
|
borderPath?.addLine(to: CGPoint(x: width, y: frame.origin.y))
|
||||||
|
borderPath?.addLine(to: CGPoint(x: width, y: height))
|
||||||
|
borderPath?.lineWidth = 1
|
||||||
|
|
||||||
|
var strokeColor: UIColor?
|
||||||
|
|
||||||
|
if errorShowing {
|
||||||
|
strokeColor = .mvmOrangeAA
|
||||||
|
bottomLine?.backgroundColor = .mvmOrangeAA
|
||||||
|
} else {
|
||||||
|
strokeColor = .mvmCoolGray3
|
||||||
|
bottomLine?.backgroundColor = .mvmBlack
|
||||||
|
}
|
||||||
|
strokeColor?.setStroke()
|
||||||
|
borderPath?.stroke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Observing Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Executes on UITextView.textDidEndEditingNotification
|
||||||
|
@objc open func dismissFieldInput() {
|
||||||
|
resignFirstResponder()
|
||||||
|
}
|
||||||
|
|
||||||
|
//#pragma Mark UITextView Delegate methods forwarding
|
||||||
|
@objc public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
|
||||||
|
|
||||||
|
return delegate?.textViewShouldBeginEditing?(textView) ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func textViewDidBeginEditing(_ textView: UITextView) {
|
||||||
|
|
||||||
|
delegate?.textViewDidBeginEditing?(textView)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||||
|
|
||||||
|
return delegate?.textView?(textView, shouldChangeTextIn: range, replacementText: text) ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func textViewDidChange(_ textView: UITextView) {
|
||||||
|
|
||||||
|
delegate?.textViewDidChange?(textView)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
|
||||||
|
return delegate?.textViewShouldEndEditing?(textView) ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func textViewDidEndEditing(_ textView: UITextView) {
|
||||||
|
|
||||||
|
delegate?.textViewDidEndEditing?(textView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MARK:- MVMCoreViewProtocol
|
||||||
|
extension TextView: MVMCoreViewProtocol {
|
||||||
|
|
||||||
|
open func updateView(_ size: CGFloat) { }
|
||||||
|
|
||||||
|
/// Will be called only once.
|
||||||
|
open func setupView() {
|
||||||
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
insetsLayoutMarginsFromSafeArea = false
|
||||||
|
clipsToBounds = true
|
||||||
|
errorShowing = false
|
||||||
|
hideBorder = false
|
||||||
|
layer.cornerRadius = CGFloat(CornerRadiusLarge)
|
||||||
|
// Disable SmartQuotes
|
||||||
|
smartQuotesType = .no
|
||||||
|
smartDashesType = .no
|
||||||
|
smartInsertDeleteType = .no
|
||||||
|
font = textFont
|
||||||
|
MVMCoreUICommonViewsUtility.addDismissToolbar(to: self, delegate: delegate)
|
||||||
|
textContainerInset = UIEdgeInsets(top: PaddingTwo, left: PaddingTwo, bottom: PaddingTwo, right: PaddingOne)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MARK:- MoleculeViewProtocol
|
||||||
|
extension TextView: MoleculeViewProtocol {
|
||||||
|
|
||||||
|
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
self.model = model
|
||||||
|
|
||||||
|
if let color = model.backgroundColor?.uiColor {
|
||||||
|
backgroundColor = color
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let model = model as? TextViewModel else { return }
|
||||||
|
|
||||||
|
if let height = model.height {
|
||||||
|
heightConstraint = heightAnchor.constraint(equalToConstant: height)
|
||||||
|
heightConstraint?.isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
text = model.text
|
||||||
|
placeholder = model.placeholder ?? ""
|
||||||
|
MVMCoreUICommonViewsUtility.addDismissToolbar(to: self, delegate: delegate)
|
||||||
|
}
|
||||||
|
|
||||||
|
open func reset() {
|
||||||
|
backgroundColor = .clear
|
||||||
|
text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
90
MVMCoreUI/BaseClasses/TextViewModel.swift
Normal file
90
MVMCoreUI/BaseClasses/TextViewModel.swift
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
//
|
||||||
|
// TextViewModel.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 4/2/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
open class TextViewModel: MoleculeModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public static var identifier: String = "textView"
|
||||||
|
public var backgroundColor: Color?
|
||||||
|
public var text: String = ""
|
||||||
|
public var accessibilityText: String?
|
||||||
|
public var textColor: Color?
|
||||||
|
public var fontStyle: LabelModel.FontStyle?
|
||||||
|
public var textAlignment: NSTextAlignment?
|
||||||
|
public var height: CGFloat?
|
||||||
|
public var placeholder: String?
|
||||||
|
public var isEditable: Bool = true
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case moleculeName
|
||||||
|
case text
|
||||||
|
case accessibilityText
|
||||||
|
case textColor
|
||||||
|
case backgroundColor
|
||||||
|
case fontStyle
|
||||||
|
case fontName
|
||||||
|
case fontSize
|
||||||
|
case textAlignment
|
||||||
|
case attributes
|
||||||
|
case height
|
||||||
|
case placeholder
|
||||||
|
case isEditable
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public init(text: String) {
|
||||||
|
self.text = text
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codec
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
required public init(from decoder: Decoder) throws {
|
||||||
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
if let text = try typeContainer.decodeIfPresent(String.self, forKey: .text) {
|
||||||
|
self.text = text
|
||||||
|
}
|
||||||
|
placeholder = try typeContainer.decodeIfPresent(String.self, forKey: .text)
|
||||||
|
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
|
||||||
|
textColor = try typeContainer.decodeIfPresent(Color.self, forKey: .textColor)
|
||||||
|
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||||
|
fontStyle = try typeContainer.decodeIfPresent(LabelModel.FontStyle.self, forKey: .fontStyle)
|
||||||
|
textAlignment = try typeContainer.decodeIfPresent(NSTextAlignment.self, forKey: .textAlignment)
|
||||||
|
height = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .height)
|
||||||
|
|
||||||
|
if let isEditable = try typeContainer.decodeIfPresent(Bool.self, forKey: .isEditable) {
|
||||||
|
self.isEditable = isEditable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
try container.encodeIfPresent(moleculeName, forKey: .moleculeName)
|
||||||
|
try container.encode(text, forKey: .text)
|
||||||
|
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
||||||
|
try container.encodeIfPresent(textColor, forKey: .textColor)
|
||||||
|
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||||
|
try container.encodeIfPresent(fontStyle, forKey: .fontStyle)
|
||||||
|
try container.encodeIfPresent(textAlignment, forKey: .textAlignment)
|
||||||
|
try container.encodeIfPresent(height, forKey: .height)
|
||||||
|
try container.encodeIfPresent(isEditable, forKey: .isEditable)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user