Commit 1acfef3f by Daniel Dahan

development: progression with TextField

parent 7c2198ec
...@@ -36,6 +36,9 @@ class ViewController: UIViewController { ...@@ -36,6 +36,9 @@ class ViewController: UIViewController {
private var emailField: ErrorTextField! private var emailField: ErrorTextField!
private var passwordField: TextField! private var passwordField: TextField!
/// A constant to layout the textFields.
private let constant: CGFloat = 32
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
view.backgroundColor = .white view.backgroundColor = .white
...@@ -48,7 +51,7 @@ class ViewController: UIViewController { ...@@ -48,7 +51,7 @@ class ViewController: UIViewController {
/// Programmatic update for the textField as it rotates. /// Programmatic update for the textField as it rotates.
override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) { override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
emailField.width = view.bounds.height - 80 emailField.width = view.bounds.height - 2 * constant
} }
/// Prepares the resign responder button. /// Prepares the resign responder button.
...@@ -56,7 +59,7 @@ class ViewController: UIViewController { ...@@ -56,7 +59,7 @@ class ViewController: UIViewController {
let btn = RaisedButton(title: "Resign", titleColor: Color.blue.base) let btn = RaisedButton(title: "Resign", titleColor: Color.blue.base)
btn.addTarget(self, action: #selector(handleResignResponderButton(button:)), for: .touchUpInside) btn.addTarget(self, action: #selector(handleResignResponderButton(button:)), for: .touchUpInside)
view.layout(btn).width(100).height(50).bottom(300).right(24) view.layout(btn).width(100).height(constant).top(24).right(24)
} }
/// Handle the resign responder button. /// Handle the resign responder button.
...@@ -68,12 +71,10 @@ class ViewController: UIViewController { ...@@ -68,12 +71,10 @@ class ViewController: UIViewController {
} }
private func prepareNameField() { private func prepareNameField() {
let d: CGFloat = 32
nameField = TextField() nameField = TextField()
nameField.text = "Daniel Dahan" nameField.text = "Daniel Dahan"
nameField.placeholder = "Name" nameField.placeholder = "Name"
nameField.detailLabel.text = "Your given name" nameField.detail = "Your given name"
nameField.textAlignment = .center nameField.textAlignment = .center
nameField.clearButtonMode = .whileEditing nameField.clearButtonMode = .whileEditing
...@@ -83,25 +84,30 @@ class ViewController: UIViewController { ...@@ -83,25 +84,30 @@ class ViewController: UIViewController {
nameField.leftView = leftView nameField.leftView = leftView
nameField.leftViewMode = .always nameField.leftViewMode = .always
view.layout(nameField).top(100).horizontally(left: d, right: d).height(d) nameField.placeholderLabel.backgroundColor = Color.green.base
view.layout(nameField).top(4 * constant).horizontally(left: constant, right: constant)
} }
private func prepareEmailField() { private func prepareEmailField() {
let d: CGFloat = 32
emailField = ErrorTextField(frame: CGRect(x: d, y: 200, width: view.width - (2 * d), height: d)) emailField = ErrorTextField(frame: CGRect(x: constant, y: 7 * constant, width: view.width - (2 * constant), height: constant))
emailField.placeholderLabel.text = "Email" emailField.text = "Daniel Dahan"
emailField.detailLabel.text = "Error, incorrect email" emailField.placeholder = "Email"
emailField.detail = "Error, incorrect email"
emailField.isClearIconButtonEnabled = true emailField.isClearIconButtonEnabled = true
emailField.textAlignment = .right
emailField.delegate = self emailField.delegate = self
let leftView = UIImageView() let leftView = UIImageView()
leftView.image = Icon.email?.tint(with: Color.cyan.base) leftView.image = Icon.email?.tint(with: Color.cyan.base)
emailField.leftView = leftView emailField.leftView = leftView
emailField.leftViewMode = .always emailField.leftViewMode = .always
emailField.placeholderLabel.backgroundColor = Color.green.base
// Set the colors for the emailField, different from the defaults.
// emailField.placeholderNormalColor = Color.amber.darken4 // emailField.placeholderNormalColor = Color.amber.darken4
// emailField.placeholderActiveColor = Color.pink.base // emailField.placeholderActiveColor = Color.pink.base
// emailField.dividerNormalColor = Color.cyan.base // emailField.dividerNormalColor = Color.cyan.base
...@@ -110,24 +116,19 @@ class ViewController: UIViewController { ...@@ -110,24 +116,19 @@ class ViewController: UIViewController {
} }
private func preparePasswordField() { private func preparePasswordField() {
let d: CGFloat = 32
passwordField = TextField() passwordField = TextField()
passwordField.placeholderLabel.text = "Password" passwordField.text = "Daniel Dahan"
passwordField.detailLabel.text = "At least 8 characters" passwordField.placeholder = "Password"
passwordField.detail = "At least 8 characters"
passwordField.clearButtonMode = .whileEditing passwordField.clearButtonMode = .whileEditing
passwordField.isVisibilityIconButtonEnabled = true passwordField.isVisibilityIconButtonEnabled = true
let leftView = UIImageView()
leftView.image = Icon.email?.tint(with: Color.cyan.base)
passwordField.leftView = leftView
passwordField.leftViewMode = .always
// Setting the visibilityIconButton color. // Setting the visibilityIconButton color.
passwordField.visibilityIconButton?.tintColor = Color.green.base.withAlphaComponent(passwordField.isSecureTextEntry ? 0.38 : 0.54) passwordField.visibilityIconButton?.tintColor = Color.green.base.withAlphaComponent(passwordField.isSecureTextEntry ? 0.38 : 0.54)
view.layout(passwordField).top(300).horizontally(left: d, right: d).height(d) passwordField.placeholderLabel.backgroundColor = Color.green.base
view.layout(passwordField).top(10 * constant).horizontally(left: constant, right: constant)
} }
} }
...@@ -162,5 +163,17 @@ extension UIViewController: TextFieldDelegate { ...@@ -162,5 +163,17 @@ extension UIViewController: TextFieldDelegate {
(textField as? ErrorTextField)?.isErrorRevealed = false (textField as? ErrorTextField)?.isErrorRevealed = false
return true return true
} }
public func textField(textField: UITextField, didChange text: String?) {
print("did change", text)
}
public func textField(textField: UITextField, willClear text: String?) {
print("will clear", text)
}
public func textField(textField: UITextField, didClear text: String?) {
print("did clear", text)
}
} }
...@@ -184,18 +184,18 @@ open class SearchBar: Bar { ...@@ -184,18 +184,18 @@ open class SearchBar: Bar {
/// Clears the textField text. /// Clears the textField text.
@objc @objc
internal func handleClearButton() { internal func handleClearButton() {
let text = textField.text let t = textField.text
delegate?.searchBar?(searchBar: self, willClear: textField, with: text) delegate?.searchBar?(searchBar: self, willClear: textField, with: t)
textField.text = nil textField.text = nil
delegate?.searchBar?(searchBar: self, didClear: textField, with: text) delegate?.searchBar?(searchBar: self, didClear: textField, with: t)
} }
// Live updates the search results. // Live updates the search results.
@objc @objc
internal func handleTextChange(textField: UITextField) { internal func handleEditingChanged(textField: UITextField) {
delegate?.searchBar?(searchBar: self, didChange: textField, with: textField.text) delegate?.searchBar?(searchBar: self, didChange: textField, with: textField.text)
} }
...@@ -209,7 +209,7 @@ open class SearchBar: Bar { ...@@ -209,7 +209,7 @@ open class SearchBar: Bar {
textColor = Color.darkText.primary textColor = Color.darkText.primary
placeholder = "Search" placeholder = "Search"
contentView.addSubview(textField) contentView.addSubview(textField)
textField.addTarget(self, action: #selector(handleTextChange(textField:)), for: .editingChanged) textField.addTarget(self, action: #selector(handleEditingChanged(textField:)), for: .editingChanged)
} }
/// Prepares the clearButton. /// Prepares the clearButton.
......
...@@ -72,8 +72,18 @@ open class TextField: UITextField { ...@@ -72,8 +72,18 @@ open class TextField: UITextField {
/// A Boolean that indicates if the TextField is in an animating state. /// A Boolean that indicates if the TextField is in an animating state.
open internal(set) var isAnimating = false open internal(set) var isAnimating = false
open override var leftView: UIView? {
didSet {
layoutSubviews()
}
}
/// The leftView width value. /// The leftView width value.
open var leftViewWidth: CGFloat { open var leftViewWidth: CGFloat {
guard nil != leftView else {
return 0
}
return leftViewOffset + height return leftViewOffset + height
} }
...@@ -150,7 +160,7 @@ open class TextField: UITextField { ...@@ -150,7 +160,7 @@ open class TextField: UITextField {
/// The placeholder UILabel. /// The placeholder UILabel.
@IBInspectable @IBInspectable
open private(set) lazy var placeholderLabel: UILabel = UILabel() open private(set) lazy var placeholderLabel = UILabel()
/// Placeholder normal text /// Placeholder normal text
@IBInspectable @IBInspectable
...@@ -321,20 +331,22 @@ open class TextField: UITextField { ...@@ -321,20 +331,22 @@ open class TextField: UITextField {
} }
open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard "placeholderLabel.text" == keyPath || "detailLabel.text" == keyPath else { guard "placeholderLabel.text" != keyPath else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) updatePlaceholderLabelColor()
return return
} }
updatePlaceholderLabelColor() guard "detailLabel.text" != keyPath else {
updateDetailLabelColor() updateDetailLabelColor()
return
}
layoutToSize() super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
} }
deinit { deinit {
removeObserver(self, forKeyPath: "detailLabel.text")
removeObserver(self, forKeyPath: "placeholderLabel.text") removeObserver(self, forKeyPath: "placeholderLabel.text")
removeObserver(self, forKeyPath: "detailLabel.text")
} }
/** /**
...@@ -365,12 +377,9 @@ open class TextField: UITextField { ...@@ -365,12 +377,9 @@ open class TextField: UITextField {
open override func layoutSubviews() { open override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
layoutDivider() layoutDivider()
layoutLeftView()
guard !isAnimating else { reload()
return
}
layoutToSize()
} }
open override func layoutSublayers(of layer: CALayer) { open override func layoutSublayers(of layer: CALayer) {
...@@ -388,6 +397,12 @@ open class TextField: UITextField { ...@@ -388,6 +397,12 @@ open class TextField: UITextField {
dividerEditingDidBeginAnimation() dividerEditingDidBeginAnimation()
placeholderEditingDidBeginAnimation() placeholderEditingDidBeginAnimation()
} }
// Live updates the textField text.
@objc
internal func handleEditingChanged(textField: UITextField) {
(delegate as? TextFieldDelegate)?.textField?(textField: self, didChange: textField.text)
}
/// Handles the text editing did end state. /// Handles the text editing did end state.
@objc @objc
...@@ -433,8 +448,7 @@ open class TextField: UITextField { ...@@ -433,8 +448,7 @@ open class TextField: UITextField {
when subclassing. when subclassing.
*/ */
open func prepare() { open func prepare() {
super.placeholder = nil clipsToBounds = false
clipsToBounds = false
borderStyle = .none borderStyle = .none
backgroundColor = nil backgroundColor = nil
contentScaleFactor = Device.scale contentScaleFactor = Device.scale
...@@ -446,12 +460,15 @@ open class TextField: UITextField { ...@@ -446,12 +460,15 @@ open class TextField: UITextField {
} }
/// Ensures that the components are sized correctly. /// Ensures that the components are sized correctly.
open func layoutToSize() { open func reload() {
layoutPlaceholderLabel() guard !isAnimating else {
return
}
layoutPlaceholderLabel()
layoutDetailLabel() layoutDetailLabel()
layoutButton(button: clearIconButton) layoutButton(button: clearIconButton)
layoutButton(button: visibilityIconButton) layoutButton(button: visibilityIconButton)
layoutLeftView()
} }
/// Layout the divider. /// Layout the divider.
...@@ -461,19 +478,18 @@ open class TextField: UITextField { ...@@ -461,19 +478,18 @@ open class TextField: UITextField {
/// Layout the placeholderLabel. /// Layout the placeholderLabel.
open func layoutPlaceholderLabel() { open func layoutPlaceholderLabel() {
let x = leftViewWidth let w = leftViewWidth
divider.contentEdgeInsets.left = x
if !isEditing && true == text?.isEmpty && isPlaceholderAnimated { if !isEditing && true == text?.isEmpty && isPlaceholderAnimated {
placeholderLabel.frame = CGRect(x: x, y: bounds.origin.y, width: bounds.width - x, height: bounds.height) placeholderLabel.frame = CGRect(x: w, y: bounds.origin.y, width: width - w, height: height)
} else if placeholderLabel.transform.isIdentity { } else if placeholderLabel.transform.isIdentity {
placeholderLabel.frame = CGRect(x: x, y: bounds.origin.y, width: bounds.width - x, height: bounds.height) placeholderLabel.frame = CGRect(x: w, y: bounds.origin.y, width: width - w, height: height)
placeholderLabel.transform = CGAffineTransform(scaleX: 0.75, y: 0.75) placeholderLabel.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
switch textAlignment { switch textAlignment {
case .left, .natural: case .left, .natural:
placeholderLabel.x = x placeholderLabel.x = w
case .right: case .right:
placeholderLabel.x = width - placeholderLabel.width - x placeholderLabel.x = width - placeholderLabel.width
default:break default:break
} }
placeholderLabel.y = -placeholderLabel.height + placeholderVerticalOffset placeholderLabel.y = -placeholderLabel.height + placeholderVerticalOffset
...@@ -481,14 +497,14 @@ open class TextField: UITextField { ...@@ -481,14 +497,14 @@ open class TextField: UITextField {
} else { } else {
switch textAlignment { switch textAlignment {
case .left, .natural: case .left, .natural:
placeholderLabel.x = x placeholderLabel.x = w
case .right: case .right:
placeholderLabel.x = width - placeholderLabel.width - x placeholderLabel.x = width - placeholderLabel.width
case .center: case .center:
placeholderLabel.center.x = (width + x) / 2 placeholderLabel.center.x = (width + w) / 2
default:break default:break
} }
placeholderLabel.width = (width - x) * 0.75 placeholderLabel.width = (width - w) * 0.75
} }
} }
...@@ -516,9 +532,13 @@ open class TextField: UITextField { ...@@ -516,9 +532,13 @@ open class TextField: UITextField {
return return
} }
v.width = leftViewWidth let w = leftViewWidth
v.width = w
v.height = height v.height = height
v.contentMode = .center v.contentMode = .center
divider.contentEdgeInsets.left = w
} }
/// The animation for the divider when editing begins. /// The animation for the divider when editing begins.
...@@ -540,9 +560,7 @@ open class TextField: UITextField { ...@@ -540,9 +560,7 @@ open class TextField: UITextField {
} }
guard placeholderLabel.transform.isIdentity else { guard placeholderLabel.transform.isIdentity else {
if isEditing { updatePlaceholderLabelColor()
placeholderLabel.textColor = placeholderActiveColor
}
return return
} }
...@@ -552,16 +570,13 @@ open class TextField: UITextField { ...@@ -552,16 +570,13 @@ open class TextField: UITextField {
return return
} }
let x = s.leftViewWidth
s.divider.contentEdgeInsets.left = x
s.placeholderLabel.transform = CGAffineTransform(scaleX: 0.75, y: 0.75) s.placeholderLabel.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
switch s.textAlignment { switch s.textAlignment {
case .left, .natural: case .left, .natural:
s.placeholderLabel.x = x s.placeholderLabel.x = s.leftViewWidth
case .right: case .right:
s.placeholderLabel.x = s.width - s.placeholderLabel.width - x s.placeholderLabel.x = s.width - s.placeholderLabel.width
default:break default:break
} }
...@@ -578,26 +593,24 @@ open class TextField: UITextField { ...@@ -578,26 +593,24 @@ open class TextField: UITextField {
return return
} }
if !placeholderLabel.transform.isIdentity && true == text?.isEmpty { guard !placeholderLabel.transform.isIdentity && true == text?.isEmpty else {
isAnimating = true updatePlaceholderLabelColor()
UIView.animate(withDuration: 0.15, animations: { [weak self] in return
guard let s = self else { }
return
} isAnimating = true
UIView.animate(withDuration: 0.15, animations: { [weak self] in
let x = s.leftViewWidth guard let s = self else {
s.divider.contentEdgeInsets.left = x return
}
s.placeholderLabel.transform = CGAffineTransform.identity
s.placeholderLabel.x = x s.placeholderLabel.transform = CGAffineTransform.identity
s.placeholderLabel.y = 0 s.placeholderLabel.x = s.leftViewWidth
s.placeholderLabel.textColor = s.placeholderNormalColor s.placeholderLabel.y = 0
}) { [weak self] _ in s.placeholderLabel.textColor = s.placeholderNormalColor
self?.isAnimating = false }) { [weak self] _ in
} self?.isAnimating = false
} else if !isEditing { }
placeholderLabel.textColor = placeholderNormalColor
}
} }
/// Prepares the divider. /// Prepares the divider.
...@@ -607,8 +620,8 @@ open class TextField: UITextField { ...@@ -607,8 +620,8 @@ open class TextField: UITextField {
/// Prepares the placeholderLabel. /// Prepares the placeholderLabel.
private func preparePlaceholderLabel() { private func preparePlaceholderLabel() {
placeholderNormalColor = Color.darkText.others
font = RobotoFont.regular(with: 16) font = RobotoFont.regular(with: 16)
placeholderNormalColor = Color.darkText.others
addSubview(placeholderLabel) addSubview(placeholderLabel)
addObserver(self, forKeyPath: "placeholderLabel.text", options: [], context: &TextFieldContext) addObserver(self, forKeyPath: "placeholderLabel.text", options: [], context: &TextFieldContext)
} }
...@@ -625,6 +638,7 @@ open class TextField: UITextField { ...@@ -625,6 +638,7 @@ open class TextField: UITextField {
/// Prepares the target handlers. /// Prepares the target handlers.
private func prepareTargetHandlers() { private func prepareTargetHandlers() {
addTarget(self, action: #selector(handleEditingDidBegin), for: .editingDidBegin) addTarget(self, action: #selector(handleEditingDidBegin), for: .editingDidBegin)
addTarget(self, action: #selector(handleEditingChanged), for: .editingChanged)
addTarget(self, action: #selector(handleEditingDidEnd), for: .editingDidEnd) addTarget(self, action: #selector(handleEditingDidEnd), for: .editingDidEnd)
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment