import UIKit | |
@IBDesignable | |
class UnderlinedTextField: UITextField { | |
@IBInspectable var borderColor: UIColor = Colors.darkText { | |
didSet { setNeedsDisplay() } | |
} | |
@IBInspectable var borderedWidth: CGFloat = 1 { | |
didSet { setNeedsDisplay() } | |
} | |
@IBInspectable var padding: CGFloat = 0 { | |
didSet { setNeedsDisplay() } | |
} | |
@IBInspectable var errorColor: UIColor = Colors.errorBackground { | |
didSet { setNeedsDisplay() } | |
} | |
var hasError: Bool = false { | |
didSet { | |
if hasError && hasError == oldValue { | |
let animation = CAKeyframeAnimation(keyPath: "transform.translation.x") | |
animation.duration = 0.3 | |
animation.repeatCount = 1 | |
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) | |
animation.values = [-10.0, 10.0, -5.0, 5.0, -2.0, 0.0] | |
placeholderView.layer.add(animation, forKey: "shake") | |
return | |
} | |
setNeedsDisplay() | |
placeholderView.textColor = hasError ? errorColor : borderColor | |
} | |
} | |
override var intrinsicContentSize: CGSize { | |
let size = super.intrinsicContentSize | |
return CGSize(width: size.width, height: size.height + 30) | |
} | |
lazy var placeholderView: UILabel = { | |
let placeholderView = UILabel() | |
placeholderView.textColor = borderColor | |
placeholderView.font = Font.semiBold.withSize(10) | |
placeholderView.text = placeholder ?? "No text" | |
placeholderView.alpha = 0.0 | |
return placeholderView | |
}() | |
var placeholderViewTopConstraint: NSLayoutConstraint? | |
override func draw(_ rect: CGRect) { | |
let path = UIBezierPath() | |
path.move(to: CGPoint(x: rect.minX + padding, y: rect.maxY)) | |
path.addLine(to: CGPoint(x: rect.maxX - padding, y: rect.maxY)) | |
path.lineWidth = borderedWidth | |
if hasError { | |
errorColor.setStroke() | |
} else { | |
borderColor.setStroke() | |
} | |
path.stroke() | |
} | |
override func didMoveToWindow() { | |
super.didMoveToWindow() | |
font = Font.semiBold.withSize(17) | |
addSubview(placeholderView) | |
placeholderView.translatesAutoresizingMaskIntoConstraints = false | |
placeholderView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true | |
placeholderViewTopConstraint = placeholderView.topAnchor.constraint(equalTo: topAnchor, constant: 5) | |
placeholderViewTopConstraint?.priority = UILayoutPriority(999) | |
placeholderViewTopConstraint?.isActive = true | |
addTarget(self, action: #selector(textDidChange), for: .editingChanged) | |
} | |
@objc func textDidChange() { | |
if text != "" { | |
placeholderViewTopConstraint?.constant = 0 | |
UIView.animate(withDuration: 0.25) { | |
self.placeholderView.alpha = 1.0 | |
self.layoutIfNeeded() | |
} | |
} else { | |
placeholderViewTopConstraint?.constant = 5 | |
UIView.animate(withDuration: 0.25) { | |
self.placeholderView.alpha = 0.0 | |
self.layoutIfNeeded() | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment