Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Commit

Permalink
Improve first responder behaviour and new style properties
Browse files Browse the repository at this point in the history
  • Loading branch information
victorBaro committed Oct 7, 2016
1 parent 5fd0c55 commit e7bf0a3
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 25 deletions.
81 changes: 56 additions & 25 deletions AnimatedTextInput/Classes/AnimatedTextInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ public class AnimatedTextInput: UIControl {
return textInput.currentText
}
set {
(newValue != nil) ? configurePlaceholderAsInactiveHint() : configurePlaceholderAsDefault()
if !textInput.view.isFirstResponder() {
(newValue != nil) ? configurePlaceholderAsInactiveHint() : configurePlaceholderAsDefault()
}
textInput.currentText = newValue
}
}
Expand All @@ -54,15 +56,16 @@ public class AnimatedTextInput: UIControl {
private let counterLabelRightMargin: CGFloat = 15
private let counterLabelTopMargin: CGFloat = 5

private var isResigningResponder = false
private var isPlaceholderAsHint = false
private var hasCounterLabel = false
private var textInput: TextInput!
private var placeholderErrorText = "Error message"
private var placeholderErrorText: String?
private var lineToBottomConstraint: NSLayoutConstraint!

private var placeholderPosition: CGPoint {
let hintPosition = CGPoint(x: style.leftMargin, y: style.yHintPositionOffset)
let defaultPosition = CGPoint(x: style.leftMargin, y: style.topMargin)
let defaultPosition = CGPoint(x: style.leftMargin, y: style.topMargin + style.yPlaceholderPositionOffset)
return isPlaceholderAsHint ? hintPosition : defaultPosition
}

Expand All @@ -89,13 +92,23 @@ public class AnimatedTextInput: UIControl {
super.updateConstraints()
}

public override func layoutSubviews() {
super.layoutSubviews()
layoutPlaceholderLayer()
}

private func layoutPlaceholderLayer() {
// Some letters like 'g' or 'á' were not rendered properly, the frame need to be about 20% higher than the font size
let frameHeightCorrectionFactor: CGFloat = 1.2
placeholderLayer.frame = CGRect(origin: placeholderPosition, size: CGSize(width: bounds.width, height: style.textInputFont.pointSize * frameHeightCorrectionFactor))
}

// MARK: Configuration
// mark: Configuration

private func addLineViewConstraints() {
pinLeading(toLeadingOf: lineView, constant: style.leftMargin)
pinTrailing(toTrailingOf: lineView, constant: style.rightMargin)
lineView.setHeight(to: lineWidth)
lineView.setHeight(to: lineWidth / UIScreen.mainScreen().scale)
let constant = hasCounterLabel ? -counterLabel.intrinsicContentSize().height - counterLabelTopMargin : 0
pinBottom(toBottomOf: lineView, constant: constant)
}
Expand All @@ -115,7 +128,7 @@ public class AnimatedTextInput: UIControl {
}

private func addLine() {
lineView.defaultColor = style.inactiveColor
lineView.defaultColor = style.lineInactiveColor
lineView.translatesAutoresizingMaskIntoConstraints = false
addSubview(lineView)
}
Expand All @@ -124,21 +137,14 @@ public class AnimatedTextInput: UIControl {
placeholderLayer.masksToBounds = false
placeholderLayer.string = placeHolderText
placeholderLayer.foregroundColor = style.inactiveColor.CGColor
let fontSize = style.textInputFont.pointSize
placeholderLayer.fontSize = fontSize
placeholderLayer.fontSize = style.textInputFont.pointSize
placeholderLayer.font = style.textInputFont
placeholderLayer.contentsScale = UIScreen.mainScreen().scale
placeholderLayer.backgroundColor = UIColor.clearColor().CGColor
// Some letters like 'g' or 'á' were not rendered properly, the frame need to be about 20% higher than the font size
placeholderLayer.frame = correctedPlacholderLayer(with: fontSize)
layoutPlaceholderLayer()
layer.addSublayer(placeholderLayer)
}

private func correctedPlacholderLayer(with fontSize: CGFloat) -> CGRect {
let frameHeightCorrectionFactor: CGFloat = 2
return CGRect(origin: placeholderPosition, size: CGSize(width: bounds.width, height: fontSize * frameHeightCorrectionFactor))
}

private func addTapGestureRecognizer() {
let tap = UITapGestureRecognizer(target: self, action: #selector(viewWasTapped(_:)))
addGestureRecognizer(tap)
Expand All @@ -162,7 +168,7 @@ public class AnimatedTextInput: UIControl {
counterLabel.text = "\(characters)/\(components[1])"
}

//MARK: States and animations
//mark: States and animations

private func configurePlaceholderAsActiveHint() {
isPlaceholderAsHint = true
Expand Down Expand Up @@ -196,7 +202,7 @@ public class AnimatedTextInput: UIControl {
lineView.fillLine(with: style.errorColor)
}

private func configurePlaceholderWith(fontSize fontSize: CGFloat, foregroundColor: CGColor, text: String) {
private func configurePlaceholderWith(fontSize fontSize: CGFloat, foregroundColor: CGColor, text: String?) {
placeholderLayer.fontSize = fontSize
placeholderLayer.foregroundColor = foregroundColor
placeholderLayer.string = text
Expand All @@ -212,17 +218,20 @@ public class AnimatedTextInput: UIControl {
//MARK: Behaviours

@objc private func viewWasTapped(sender: UIGestureRecognizer) {
if let tapAction = tapAction { tapAction() }
else { becomeFirstResponder() }
if let tapAction = tapAction {
tapAction()
} else {
becomeFirstResponder()
}
}

private func styleDidChange() {
lineView.defaultColor = style.inactiveColor
lineView.defaultColor = style.lineInactiveColor
placeholderLayer.foregroundColor = style.inactiveColor.CGColor
let fontSize = style.textInputFont.pointSize
placeholderLayer.fontSize = fontSize
placeholderLayer.font = style.textInputFont
placeholderLayer.frame = correctedPlacholderLayer(with: fontSize)
layoutPlaceholderLayer()
textInput.view.tintColor = style.activeColor
textInput.textColor = style.textInputFontColor
textInput.font = style.textInputFont
Expand All @@ -234,34 +243,44 @@ public class AnimatedTextInput: UIControl {
isActive = true
textInput.view.becomeFirstResponder()
counterLabel.textColor = style.activeColor
placeholderErrorText = nil
animatePlaceholder(to: configurePlaceholderAsActiveHint)
return true
}

override public func resignFirstResponder() -> Bool {
guard !isResigningResponder else { return true }
isActive = false
isResigningResponder = true
textInput.view.resignFirstResponder()
isResigningResponder = false
counterLabel.textColor = style.inactiveColor

if let textInputError = textInput as? TextInputError {
textInputError.removeErrorHintMessage()
}

// If the placeholder is showing an error we want to keep this state. Otherwise revert to inactive state.
if placeholderErrorText == nil {
animateToInactiveState()
}
return true
}

private func animateToInactiveState() {
guard let text = textInput.currentText where !text.isEmpty else {
animatePlaceholder(to: configurePlaceholderAsDefault)
return true
return
}
animatePlaceholder(to: configurePlaceholderAsInactiveHint)
return true
}



override public func canResignFirstResponder() -> Bool {
return textInput.view.canResignFirstResponder()
}

override public func canBecomeFirstResponder() -> Bool {
guard !isResigningResponder else { return false }
return textInput.view.canBecomeFirstResponder()
}

Expand All @@ -273,6 +292,18 @@ public class AnimatedTextInput: UIControl {
animatePlaceholder(to: configurePlaceholderAsErrorHint)
}

public func clearError() {
placeholderErrorText = nil
if let textInputError = textInput as? TextInputError {
textInputError.removeErrorHintMessage()
}
if isActive {
animatePlaceholder(to: configurePlaceholderAsActiveHint)
} else {
animateToInactiveState()
}
}

private func configureType() {
textInput.view.removeFromSuperview()
addTextInput()
Expand Down
4 changes: 4 additions & 0 deletions AnimatedTextInput/Classes/AnimatedTextInputStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import UIKit
public protocol AnimatedTextInputStyle {
var activeColor: UIColor { get }
var inactiveColor: UIColor { get }
var lineInactiveColor: UIColor { get }
var errorColor: UIColor { get }
var textInputFont: UIFont { get }
var textInputFontColor: UIColor { get }
Expand All @@ -13,12 +14,14 @@ public protocol AnimatedTextInputStyle {
var rightMargin: CGFloat { get }
var bottomMargin: CGFloat { get }
var yHintPositionOffset: CGFloat { get }
var yPlaceholderPositionOffset: CGFloat { get }
}

public struct AnimatedTextInputStyleBlue: AnimatedTextInputStyle {

public let activeColor = UIColor(red: 51.0/255.0, green: 175.0/255.0, blue: 236.0/255.0, alpha: 1.0)
public let inactiveColor = UIColor.grayColor().colorWithAlphaComponent(0.5)
public let lineInactiveColor = UIColor.grayColor().colorWithAlphaComponent(0.2)
public let errorColor = UIColor.redColor()
public let textInputFont = UIFont.systemFontOfSize(14)
public let textInputFontColor = UIColor.blackColor()
Expand All @@ -29,6 +32,7 @@ public struct AnimatedTextInputStyleBlue: AnimatedTextInputStyle {
public let rightMargin: CGFloat = 0
public let bottomMargin: CGFloat = 10
public let yHintPositionOffset: CGFloat = 7
public let yPlaceholderPositionOffset: CGFloat = 0

public init() { }
}
2 changes: 2 additions & 0 deletions Example/AnimatedTextInput/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct CustomTextInputStyle: AnimatedTextInputStyle {

let activeColor = UIColor.orangeColor()
let inactiveColor = UIColor.grayColor().colorWithAlphaComponent(0.3)
let lineInactiveColor = UIColor.grayColor().colorWithAlphaComponent(0.3)
let errorColor = UIColor.redColor()
let textInputFont = UIFont.systemFontOfSize(14)
let textInputFontColor = UIColor.blackColor()
Expand All @@ -71,4 +72,5 @@ struct CustomTextInputStyle: AnimatedTextInputStyle {
let rightMargin: CGFloat = 0
let bottomMargin: CGFloat = 10
let yHintPositionOffset: CGFloat = 7
let yPlaceholderPositionOffset: CGFloat = 0
}

0 comments on commit e7bf0a3

Please sign in to comment.