Issue #325
- Use
UILabel
as placeholder and move it - When label is moved up, scale it down 80%. It means it has 10% padding on the left and right when shrinked, so
offsetX
for translation is 10% - Translation transform should happen before scale
- Ideally we can animate font and color change using
CATextLayer
, but withUILabel
we can useUIView.transition
final class MaterialInputView: UIView {
lazy var label: UILabel = {
return UILabel()
}()
lazy var textField: UITextField = {
let textField = UITextField()
textField.tintColor = R.color.primary
textField.textColor = R.color.lightText
textField.font = R.customFont.medium(16)
textField.autocapitalizationType = .none
textField.autocorrectionType = .no
return textField
}()
lazy var line: UIView = {
let line = UIView()
line.backgroundColor = R.color.primary
return line
}()
// Whether label should be moved to top
private var isUp: Bool = false {
didSet {
styleLabel(isUp: isUp)
moveLabel(isUp: isUp)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError()
}
private func setup() {
addSubviews([textField, label, line])
textField.delegate = self
NSLayoutConstraint.on([
textField.leftAnchor.constraint(equalTo: leftAnchor, constant: 16),
textField.rightAnchor.constraint(equalTo: rightAnchor, constant: -16),
textField.topAnchor.constraint(equalTo: topAnchor, constant: 16),
label.leftAnchor.constraint(equalTo: textField.leftAnchor),
label.centerYAnchor.constraint(equalTo: textField.centerYAnchor),
line.leftAnchor.constraint(equalTo: textField.leftAnchor),
line.rightAnchor.constraint(equalTo: textField.rightAnchor),
line.topAnchor.constraint(equalTo: textField.bottomAnchor, constant: 8),
line.heightAnchor.constraint(equalToConstant: 2)
])
styleLabel(isUp: false)
}
private func styleLabel(isUp: Bool) {
UIView.transition(
with: label,
duration: 0.15,
options: .curveEaseInOut,
animations: {
if isUp {
self.label.font = R.customFont.regular(12)
self.label.textColor = R.color.primary
} else {
self.label.font = R.customFont.medium(16)
self.label.textColor = R.color.grayText
}
},
completion: nil
)
}
private func moveLabel(isUp: Bool) {
UIView.animate(
withDuration: 0.15,
delay: 0,
options: .curveEaseInOut,
animations: {
if isUp {
let offsetX = self.label.frame.width * 0.1
let translation = CGAffineTransform(translationX: -offsetX, y: -24)
let scale = CGAffineTransform(scaleX: 0.8, y: 0.8)
self.label.transform = translation.concatenating(scale)
} else {
self.label.transform = .identity
}
},
completion: nil
)
}
}
extension MaterialInputView: UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
if !isUp {
isUp = true
}
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
guard let text = textField.text else {
return false
}
if isUp && text.isEmpty {
isUp = false
}
return true
}
}