Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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