functioning border

This commit is contained in:
Kevin G Christiano 2020-04-28 16:44:05 -04:00
parent 077d94edd1
commit 2a251649af
3 changed files with 303 additions and 55 deletions

View File

@ -51,7 +51,7 @@ public protocol TextInputDidDeleteProtocol: class {
public func initialSetup() {
if !initialSetupPerformed {
tintColor = .black
tintColor = .mvmBlack
initialSetupPerformed = true
setupView()
}
@ -87,7 +87,9 @@ extension TextField: MVMCoreViewProtocol {
/// MARK:- MoleculeViewProtocol
extension TextField: MoleculeViewProtocol {
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
if let color = model.backgroundColor?.uiColor {
backgroundColor = color
}

View File

@ -9,7 +9,7 @@
import UIKit
@objc open class TextView: UITextView, UITextViewDelegate {
@objc open class TextView: UITextView, UITextViewDelegate, MVMCoreViewProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -28,6 +28,98 @@ import UIKit
return model as? TextViewModel
}
//--------------------------------------------------
// MARK: - Drawing Properties
//--------------------------------------------------
/// Total control over the drawn top, bottom, left and right borders.
public var disableAllBorders = false
private(set) var fieldState: FieldState = .original {
didSet (oldState) {
// Will not update if new state is the same as old.
if fieldState != oldState {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.fieldState.setStateUI(for: self)
}
}
}
}
/// Determines if the top, left, and right borders should be drawn.
private var hideBorders = false
public var borderStrokeColor: UIColor = .mvmCoolGray3
public var bottomStrokeColor: UIColor = .mvmBlack
private var borderPath: UIBezierPath = UIBezierPath()
private var bottomPath: UIBezierPath = UIBezierPath()
//--------------------------------------------------
// MARK: - Property Observers
//--------------------------------------------------
private var _isEnabled: Bool = true
private var _showError: Bool = false
private var _isLocked: Bool = false
private var _isSelected: Bool = false
public var isEnabled: Bool {
get { return _isEnabled }
set (enabled) {
_isEnabled = enabled
_isLocked = false
_isSelected = false
_showError = false
fieldState = enabled ? .original : .disabled
}
}
public var showError: Bool {
get { return _showError }
set (error) {
_showError = error
_isEnabled = true
_isLocked = false
_isSelected = false
fieldState = error ? .error : .original
}
}
public var isLocked: Bool {
get { return _isLocked }
set (locked) {
_isLocked = locked
_isEnabled = true
_isSelected = false
_showError = false
fieldState = locked ? .locked : .original
}
}
public var isSelected: Bool {
get { return _isSelected }
set (selected) {
_isSelected = selected
_isLocked = false
_isEnabled = true
if _showError {
fieldState = selected ? .selectedError : .error
} else {
fieldState = selected ? .selected : .original
}
}
}
//--------------------------------------------------
// MARK: - Delegate
//--------------------------------------------------
@ -47,6 +139,8 @@ import UIKit
}
}
var delegateObject: MVMCoreUIDelegateObject?
//--------------------------------------------------
// MARK: - Constraint
//--------------------------------------------------
@ -77,7 +171,7 @@ import UIKit
}
//--------------------------------------------------
// MARK: - Setup
// MARK: - Lifecycle
//--------------------------------------------------
public func initialSetup() {
@ -89,6 +183,187 @@ import UIKit
}
}
open func updateView(_ size: CGFloat) {
refreshUI()
}
/// Will be called only once.
open func setupView() {
translatesAutoresizingMaskIntoConstraints = false
insetsLayoutMarginsFromSafeArea = false
showsVerticalScrollIndicator = false
showsHorizontalScrollIndicator = false
contentInset = UIEdgeInsets(top: Padding.Three, left: Padding.Three, bottom: Padding.Three, right: Padding.Three)
backgroundColor = .mvmWhite
clipsToBounds = true
smartQuotesType = .no
smartDashesType = .no
smartInsertDeleteType = .no
font = textViewModel?.fontStyle.getFont()
isEditable = true
isOpaque = false
}
open func reset() {
backgroundColor = .mvmWhite
text = ""
inputAccessoryView?.removeFromSuperview()
contentInset = UIEdgeInsets(top: Padding.Three, left: Padding.Three, bottom: Padding.Three, right: Padding.Three)
}
open override func layoutSubviews() {
super.layoutSubviews()
refreshUI(bottomBarSize: showError ? 4 : 1)
}
//--------------------------------------------------
// MARK: - Draw
//--------------------------------------------------
/// This handles the top, left, and right border lines.
open override func draw(_ rect: CGRect) {
super.draw(rect)
borderPath.removeAllPoints()
bottomPath.removeAllPoints()
if !disableAllBorders && !hideBorders {
// Brings the other half of the line inside the view to prevent cropping.
let origin = bounds.origin
let size = frame.size
let insetLean: CGFloat = 0.5
borderPath.lineWidth = 1
borderPath.move(to: CGPoint(x: origin.x + insetLean, y: origin.y + size.height))
borderPath.addLine(to: CGPoint(x: origin.x + insetLean, y: origin.y + insetLean))
borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + insetLean))
borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + size.height))
borderStrokeColor.setStroke()
borderPath.stroke()
bottomPath.lineWidth = 4
bottomPath.move(to: CGPoint(x: origin.x + size.width, y: origin.y + size.height - 2))
bottomPath.addLine(to: CGPoint(x: origin.x, y: origin.y + size.height - 2))
bottomStrokeColor.setStroke()
bottomPath.stroke()
}
}
//--------------------------------------------------
// MARK: - Draw States
//--------------------------------------------------
public enum FieldState {
case original
case error
case selectedError
case selected
case locked
case disabled
public func setStateUI(for formField: TextView) {
switch self {
case .original:
formField.originalUI()
case .error:
formField.errorUI()
case .selectedError:
formField.selectedErrorUI()
case .selected:
formField.selectedUI()
case .locked:
formField.lockedUI()
case .disabled:
formField.disabledUI()
}
}
}
open func originalUI() {
isEditable = true
hideBorders = false
borderStrokeColor = .mvmCoolGray3
bottomStrokeColor = .mvmBlack
refreshUI(bottomBarSize: 1)
}
open func errorUI() {
isEditable = true
hideBorders = false
borderStrokeColor = .mvmOrange
bottomStrokeColor = .mvmOrange
refreshUI(bottomBarSize: 4)
}
open func selectedErrorUI() {
isEditable = true
hideBorders = false
borderStrokeColor = .mvmBlack
bottomStrokeColor = .mvmOrange
refreshUI(bottomBarSize: 4)
}
open func selectedUI() {
isEditable = true
hideBorders = false
borderStrokeColor = .mvmBlack
bottomStrokeColor = .mvmBlack
refreshUI(bottomBarSize: 1)
}
open func lockedUI() {
isEditable = false
hideBorders = true
borderStrokeColor = .clear
bottomStrokeColor = .clear
refreshUI(bottomBarSize: 1)
}
open func disabledUI() {
isEditable = false
hideBorders = false
borderStrokeColor = .mvmCoolGray3
bottomStrokeColor = .mvmCoolGray3
refreshUI(bottomBarSize: 1)
}
open func refreshUI(bottomBarSize: CGFloat? = nil, updateMoleculeLayout: Bool = false) {
if !disableAllBorders {
// let size: CGFloat = bottomBarSize ?? (showError ? 4 : 1)
// var heightChanged = false
// if let bottomHeight = bottomBar?.bounds.height {
// heightChanged = size != bottomHeight
// }
if updateMoleculeLayout {//|| heightChanged {
delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self)
}
setNeedsDisplay()
layoutIfNeeded()
}
}
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
@ -177,36 +452,12 @@ import UIKit
}
}
/// MARK:- MVMCoreViewProtocol
extension TextView: MVMCoreViewProtocol {
open func updateView(_ size: CGFloat) { }
/// Will be called only once.
open func setupView() {
translatesAutoresizingMaskIntoConstraints = false
insetsLayoutMarginsFromSafeArea = false
showsVerticalScrollIndicator = false
showsHorizontalScrollIndicator = false
contentInset = UIEdgeInsets(top: Padding.Three, left: Padding.Three, bottom: Padding.Three, right: Padding.Three)
backgroundColor = .mvmWhite
clipsToBounds = true
smartQuotesType = .no
smartDashesType = .no
smartInsertDeleteType = .no
font = textViewModel?.fontStyle.getFont()
layer.borderWidth = 1
layer.borderColor = UIColor.mvmBlack.cgColor
isEditable = true
}
}
/// MARK:- MoleculeViewProtocol
// MARK:- MoleculeViewProtocol
extension TextView: MoleculeViewProtocol {
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
self.model = model
self.delegateObject = delegateObject
if let color = model.backgroundColor?.uiColor {
backgroundColor = color
@ -223,8 +474,6 @@ extension TextView: MoleculeViewProtocol {
isEditable = model.isEditable
textAlignment = model.textAlignment
textColor = model.textColor.uiColor
layer.borderColor = model.borderColor?.cgColor
layer.borderWidth = model.borderWidth
text = model.text
uiTextViewDelegate = delegateObject?.uiTextViewDelegate
isShowingPlaceholder = model.text!.isEmpty
@ -237,17 +486,14 @@ extension TextView: MoleculeViewProtocol {
setPlaceholderIfAvailable()
if isEditable {
FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
MVMCoreUICommonViewsUtility.addDismissToolbar(to: self, delegate: delegateObject?.uiTextViewDelegate)
if model.selected ?? false {
isSelected = true
model.wasInitiallySelected = true
becomeFirstResponder()
}
}
}
open func reset() {
backgroundColor = .mvmWhite
text = ""
inputAccessoryView?.removeFromSuperview()
layer.borderColor = UIColor.mvmBlack.cgColor
contentInset = UIEdgeInsets(top: Padding.Three, left: Padding.Three, bottom: Padding.Three, right: Padding.Three)
layer.borderWidth = 0
}
}

View File

@ -27,8 +27,8 @@ open class TextViewModel: TextEntryFieldModel {
public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro
public var showsPlaceholder: Bool = true
public var isEditable: Bool = true
public var borderColor: Color?
public var borderWidth: CGFloat = 0
// public var borderColor: Color?
// public var borderWidth: CGFloat = 0
//--------------------------------------------------
// MARK: - Keys
@ -44,12 +44,12 @@ open class TextViewModel: TextEntryFieldModel {
case textAlignment
case attributes
case height
case borderColor
case borderWidth
case placeholder
// case borderColor
// case borderWidth
// case placeholder
case placeholderFontStyle
case isEditable = "editable"
case hideBlinkingCaret
// case hideBlinkingCaret
}
//--------------------------------------------------
@ -76,15 +76,15 @@ open class TextViewModel: TextEntryFieldModel {
self.isEditable = isEditable
}
if let borderWidth = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .borderWidth) {
self.borderWidth = borderWidth
}
// if let borderWidth = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .borderWidth) {
// self.borderWidth = borderWidth
// }
if let fontStyle = try typeContainer.decodeIfPresent(Styler.Font.self, forKey: .fontStyle) {
self.fontStyle = fontStyle
}
borderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .borderColor)
// borderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .borderColor)
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
height = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .height)
}
@ -95,13 +95,13 @@ open class TextViewModel: TextEntryFieldModel {
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
try container.encodeIfPresent(textColor, forKey: .textColor)
try container.encodeIfPresent(fontStyle, forKey: .fontStyle)
try container.encodeIfPresent(borderColor, forKey: .borderColor)
// try container.encodeIfPresent(borderColor, forKey: .borderColor)
try container.encodeIfPresent(height, forKey: .height)
try container.encode(text, forKey: .text)
try container.encode(placeholder, forKey: .placeholder)
// try container.encode(placeholder, forKey: .placeholder)
try container.encode(placeholderFontStyle, forKey: .placeholderFontStyle)
try container.encode(textAlignment, forKey: .textAlignment)
try container.encode(isEditable, forKey: .isEditable)
try container.encode(borderWidth, forKey: .borderWidth)
// try container.encode(borderWidth, forKey: .borderWidth)
}
}