Я пытаюсь создать плавающую метку, подобную этой: https://dribbble.com/shots/1254439--GIF-Float-Label-Form-Interaction
Я получил приличное количество фактических функций, но у меня проблема с собственно анимационная часть.
Вот мой код:
import UIKit
class FloatingLabelInput: UITextField {
var floatingLabel: UILabel!// = UILabel(frame: CGRect.zero)
var floatingLabelHeight: CGFloat = 14
var button = UIButton(type: .custom)
var imageView = UIImageView(frame: CGRect.zero)
@IBInspectable
var _placeholder: String?
@IBInspectable
var floatingLabelColor: UIColor = UIColor.black {
didSet {
self.floatingLabel.textColor = floatingLabelColor
self.setNeedsDisplay()
}
}
@IBInspectable
var activeBorderColor: UIColor = UIColor.blue
@IBInspectable
var floatingLabelBackground: UIColor = Theme.current.backgroundColor {
didSet {
self.floatingLabel.backgroundColor = self.floatingLabelBackground
self.setNeedsDisplay()
}
}
@IBInspectable
var floatingLabelFont: UIFont = UIFont.systemFont(ofSize: 8) {
didSet {
self.floatingLabel.font = self.floatingLabelFont
self.font = self.floatingLabelFont
self.setNeedsDisplay()
}
}
@IBInspectable
var _backgroundColor: UIColor = Theme.current.backgroundColor {
didSet {
self.layer.backgroundColor = self._backgroundColor.cgColor
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self._placeholder = (self._placeholder != nil) ? self._placeholder : placeholder
placeholder = self._placeholder // Make sure the placeholder is shown
self.floatingLabel = UILabel(frame: CGRect.zero)
self.addTarget(self, action: #selector(self.addFloatingLabel), for: .editingDidBegin)
self.addTarget(self, action: #selector(self.removeFloatingLabel), for: .editingDidEnd)
self.addTarget(self, action: #selector(self.colorFloatingLabel), for: .editingDidBegin)
self.addTarget(self, action: #selector(self.removeColorFloatingLabel), for: .editingDidEnd)
}
@objc func colorFloatingLabel() {
UIView.animate(withDuration: 1.0, delay: 0.0, options: .curveEaseInOut, animations: {
self.floatingLabel.textColor = UIColor.systemBlue
})
}
@objc func removeColorFloatingLabel() {
UIView.animate(withDuration: 1.0, delay: 0.0, options: .curveEaseInOut, animations: {
self.floatingLabel.textColor = Theme.current.grays
})
}
// Add a floating label to the view on becoming first responder
@objc func addFloatingLabel() {
if self.text == "" {
UIView.animate(withDuration: 0.2, delay: 0.0, options: .transitionCurlUp, animations: {
self.floatingLabel.textColor = self.floatingLabelColor
self.floatingLabel.font = self.floatingLabelFont
self.floatingLabel.text = self._placeholder
self.floatingLabel.layer.backgroundColor = UIColor.white.cgColor
self.floatingLabel.translatesAutoresizingMaskIntoConstraints = false
self.floatingLabel.clipsToBounds = true
self.floatingLabel.textAlignment = .center
self.floatingLabel.frame = CGRect(x: 0, y: 0, width: self.floatingLabel.frame.width+4, height: self.floatingLabel.frame.height+2)
self.layer.borderColor = self.activeBorderColor.cgColor
self.addSubview(self.floatingLabel)
self.floatingLabel.bottomAnchor.constraint(equalTo: self.topAnchor, constant: -2).isActive = true // Place our label 10 pts above the text field
self.placeholder = ""
})
}
// Floating label may be stuck behind text input. we bring it forward as it was the last item added to the view heirachy
self.bringSubviewToFront(subviews.last!)
self.setNeedsDisplay()
}
@objc func removeFloatingLabel() {
if self.text == "" {
UIView.animate(withDuration: 0.2, delay: 0.0, options: .transitionCurlDown, animations: {
self.subviews.forEach{ $0.removeFromSuperview() }
self.setNeedsDisplay()
})
self.placeholder = self._placeholder
}
self.layer.borderColor = UIColor.black.cgColor
}
func addViewPasswordButton() {
self.button.setImage(UIImage(named: "ic_reveal"), for: .normal)
self.button.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.button.frame = CGRect(x: 0, y: 16, width: 22, height: 16)
self.button.clipsToBounds = true
self.rightView = self.button
self.rightViewMode = .always
self.button.addTarget(self, action: #selector(self.enablePasswordVisibilityToggle), for: .touchUpInside)
}
func addImage(image: UIImage){
self.imageView.image = image
self.imageView.frame = CGRect(x: 20, y: 0, width: 20, height: 20)
self.imageView.translatesAutoresizingMaskIntoConstraints = true
self.imageView.contentMode = .scaleAspectFit
self.imageView.clipsToBounds = true
DispatchQueue.main.async {
self.leftView = self.imageView
self.leftViewMode = .always
}
}
@objc func enablePasswordVisibilityToggle() {
isSecureTextEntry.toggle()
if isSecureTextEntry {
self.button.setImage(UIImage(named: "ic_show"), for: .normal)
}else{
self.button.setImage(UIImage(named: "ic_hide"), for: .normal)
}
}
}
Как вы можете видеть здесь, я пробовал UIView.animate, но все, что он делает, это перемещает его вниз, как показано здесь (я изменил продолжительность UIView.animate, чтобы анимация была действительно видимой): https://m.imgur.com/a/UxSLqBK
Вместо этого я хочу, чтобы анимация была такой: https://github.com/Skyscanner/SkyFloatingLabelTextField/blob/master/SkyFloatingLabelTextField/images/example-1.gif