From 0d835cd103339762431c691bb9e8b56dd48fbc39 Mon Sep 17 00:00:00 2001 From: Kevin Seidel Date: Wed, 12 Apr 2017 11:42:07 +0200 Subject: [PATCH 1/6] Update code style to common Swift style Omitted `self` where possible and update spacing after colons --- Sources/SkyFloatingLabelTextField.swift | 295 +++++++++--------- .../SkyFloatingLabelTextFieldWithIcon.swift | 56 ++-- Sources/UITextField+fixCaretPosition.swift | 10 +- 3 files changed, 178 insertions(+), 183 deletions(-) diff --git a/Sources/SkyFloatingLabelTextField.swift b/Sources/SkyFloatingLabelTextField.swift index 99c62a1..e53d78c 100644 --- a/Sources/SkyFloatingLabelTextField.swift +++ b/Sources/SkyFloatingLabelTextField.swift @@ -16,35 +16,35 @@ open class SkyFloatingLabelTextField: UITextField { /// A Boolean value that determines if the language displayed is LTR. Default value set automatically from the application language settings. open var isLTRLanguage = UIApplication.shared.userInterfaceLayoutDirection == .leftToRight { didSet { - self.updateTextAligment() + updateTextAligment() } } fileprivate func updateTextAligment() { - if(self.isLTRLanguage) { - self.textAlignment = .left + if isLTRLanguage { + textAlignment = .left } else { - self.textAlignment = .right + textAlignment = .right } } // MARK: Animation timing /// The value of the title appearing duration - dynamic open var titleFadeInDuration:TimeInterval = 0.2 + dynamic open var titleFadeInDuration: TimeInterval = 0.2 /// The value of the title disappearing duration - dynamic open var titleFadeOutDuration:TimeInterval = 0.3 + dynamic open var titleFadeOutDuration: TimeInterval = 0.3 // MARK: Colors - fileprivate var cachedTextColor:UIColor? + fileprivate var cachedTextColor: UIColor? /// A UIColor value that determines the text color of the editable text @IBInspectable - override dynamic open var textColor:UIColor? { + override dynamic open var textColor: UIColor? { set { - self.cachedTextColor = newValue - self.updateControl(false) + cachedTextColor = newValue + updateControl(false) } get { return cachedTextColor @@ -54,86 +54,86 @@ open class SkyFloatingLabelTextField: UITextField { /// A UIColor value that determines text color of the placeholder label @IBInspectable dynamic open var placeholderColor:UIColor = UIColor.lightGray { didSet { - self.updatePlaceholder() + updatePlaceholder() } } /// A UIColor value that determines text color of the placeholder label - @IBInspectable dynamic open var placeholderFont:UIFont? { + @IBInspectable dynamic open var placeholderFont: UIFont? { didSet { - self.updatePlaceholder() + updatePlaceholder() } } fileprivate func updatePlaceholder() { if let - placeholder = self.placeholder, - let font = self.placeholderFont ?? self.font { - self.attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [NSForegroundColorAttributeName:placeholderColor, + placeholder = placeholder, + let font = placeholderFont ?? font { + attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [NSForegroundColorAttributeName: placeholderColor, NSFontAttributeName: font]) } } /// A UIColor value that determines the text color of the title label when in the normal state - @IBInspectable dynamic open var titleColor:UIColor = UIColor.gray { + @IBInspectable dynamic open var titleColor: UIColor = .gray { didSet { - self.updateTitleColor() + updateTitleColor() } } /// A UIColor value that determines the color of the bottom line when in the normal state - @IBInspectable dynamic open var lineColor:UIColor = UIColor.lightGray { + @IBInspectable dynamic open var lineColor: UIColor = .lightGray { didSet { - self.updateLineView() + updateLineView() } } /// A UIColor value that determines the color used for the title label and the line when the error message is not `nil` - @IBInspectable dynamic open var errorColor:UIColor = UIColor.red { + @IBInspectable dynamic open var errorColor: UIColor = .red { didSet { - self.updateColors() + updateColors() } } /// A UIColor value that determines the text color of the title label when editing - @IBInspectable dynamic open var selectedTitleColor:UIColor = UIColor.blue { + @IBInspectable dynamic open var selectedTitleColor: UIColor = .blue { didSet { - self.updateTitleColor() + updateTitleColor() } } /// A UIColor value that determines the color of the line in a selected state - @IBInspectable dynamic open var selectedLineColor:UIColor = UIColor.black { + @IBInspectable dynamic open var selectedLineColor: UIColor = .black { didSet { - self.updateLineView() + updateLineView() } } // MARK: Line height /// A CGFloat value that determines the height for the bottom line when the control is in the normal state - @IBInspectable dynamic open var lineHeight:CGFloat = 0.5 { + @IBInspectable dynamic open var lineHeight: CGFloat = 0.5 { didSet { - self.updateLineView() - self.setNeedsDisplay() + updateLineView() + setNeedsDisplay() } } /// A CGFloat value that determines the height for the bottom line when the control is in a selected state - @IBInspectable dynamic open var selectedLineHeight:CGFloat = 1.0 { + @IBInspectable dynamic open var selectedLineHeight: CGFloat = 1.0 { didSet { - self.updateLineView() - self.setNeedsDisplay() + updateLineView() + setNeedsDisplay() } } // MARK: View components /// The internal `UIView` to display the line below the text input. - open var lineView:UIView! + open var lineView: UIView! /// The internal `UILabel` that displays the selected, deselected title or the error message based on the current state. - open var titleLabel:UILabel! + open var titleLabel: UILabel! // MARK: Properties @@ -141,17 +141,17 @@ open class SkyFloatingLabelTextField: UITextField { The formatter to use before displaying content in the title label. This can be the `title`, `selectedTitle` or the `errorMessage`. The default implementation converts the text to uppercase. */ - open var titleFormatter:((String) -> String) = { (text:String) -> String in + open var titleFormatter: ((String) -> String) = { (text: String) -> String in return text.uppercased() } /** Identifies whether the text object should hide the text being entered. */ - override open var isSecureTextEntry:Bool { + override open var isSecureTextEntry: Bool { set { super.isSecureTextEntry = newValue - self.fixCaretPosition() + fixCaretPosition() } get { return super.isSecureTextEntry @@ -159,9 +159,9 @@ open class SkyFloatingLabelTextField: UITextField { } /// A String value for the error message to display. - open var errorMessage:String? { + open var errorMessage: String? { didSet { - self.updateControl(true) + updateControl(true) } } @@ -169,38 +169,38 @@ open class SkyFloatingLabelTextField: UITextField { fileprivate var _highlighted = false /// A Boolean value that determines whether the receiver is highlighted. When changing this value, highlighting will be done with animation - override open var isHighlighted:Bool { + override open var isHighlighted: Bool { get { return _highlighted } set { _highlighted = newValue - self.updateTitleColor() - self.updateLineView() + updateTitleColor() + updateLineView() } } /// A Boolean value that determines whether the textfield is being edited or is selected. - open var editingOrSelected:Bool { + open var editingOrSelected: Bool { get { - return super.isEditing || self.isSelected; + return super.isEditing || isSelected } } /// A Boolean value that determines whether the receiver has an error message. - open var hasErrorMessage:Bool { + open var hasErrorMessage: Bool { get { - return self.errorMessage != nil && self.errorMessage != "" + return errorMessage != nil && errorMessage != "" } } - fileprivate var _renderingInInterfaceBuilder:Bool = false + fileprivate var _renderingInInterfaceBuilder: Bool = false /// The text content of the textfield @IBInspectable - override open var text:String? { + override open var text: String? { didSet { - self.updateControl(false) + updateControl(false) } } @@ -209,32 +209,32 @@ open class SkyFloatingLabelTextField: UITextField { The placeholder can also appear in the title label when both `title` `selectedTitle` and are `nil`. */ @IBInspectable - override open var placeholder:String? { + override open var placeholder: String? { didSet { - self.setNeedsDisplay() - self.updatePlaceholder() - self.updateTitleLabel() + setNeedsDisplay() + updatePlaceholder() + updateTitleLabel() } } /// The String to display when the textfield is editing and the input is not empty. - @IBInspectable open var selectedTitle:String? { + @IBInspectable open var selectedTitle: String? { didSet { - self.updateControl() + updateControl() } } /// The String to display when the textfield is not editing and the input is not empty. - @IBInspectable open var title:String? { + @IBInspectable open var title: String? { didSet { - self.updateControl() + updateControl() } } // Determines whether the field is selected. When selected, the title floats above the textbox. - open override var isSelected:Bool { + open override var isSelected: Bool { didSet { - self.updateControl(true) + updateControl(true) } } @@ -246,7 +246,7 @@ open class SkyFloatingLabelTextField: UITextField { */ override public init(frame: CGRect) { super.init(frame: frame) - self.init_SkyFloatingLabelTextField() + init_SkyFloatingLabelTextField() } /** @@ -255,16 +255,16 @@ open class SkyFloatingLabelTextField: UITextField { */ required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - self.init_SkyFloatingLabelTextField() + init_SkyFloatingLabelTextField() } fileprivate final func init_SkyFloatingLabelTextField() { - self.borderStyle = .none - self.createTitleLabel() - self.createLineView() - self.updateColors() - self.addEditingChangedObserver() - self.updateTextAligment() + borderStyle = .none + createTitleLabel() + createLineView() + updateColors() + addEditingChangedObserver() + updateTextAligment() } fileprivate func addEditingChangedObserver() { @@ -284,29 +284,31 @@ open class SkyFloatingLabelTextField: UITextField { fileprivate func createTitleLabel() { let titleLabel = UILabel() titleLabel.autoresizingMask = [.flexibleWidth, .flexibleHeight] - titleLabel.font = UIFont.systemFont(ofSize: 13) + titleLabel.font = .systemFont(ofSize: 13) titleLabel.alpha = 0.0 - titleLabel.textColor = self.titleColor - self.addSubview(titleLabel) + titleLabel.textColor = titleColor + + addSubview(titleLabel) self.titleLabel = titleLabel } fileprivate func createLineView() { - if self.lineView == nil { + if lineView == nil { let lineView = UIView() lineView.isUserInteractionEnabled = false self.lineView = lineView - self.configureDefaultLineHeight() + configureDefaultLineHeight() } + lineView.autoresizingMask = [.flexibleWidth, .flexibleTopMargin] - self.addSubview(lineView) + addSubview(lineView) } fileprivate func configureDefaultLineHeight() { - let onePixel:CGFloat = 1.0 / UIScreen.main.scale - self.lineHeight = 2.0 * onePixel - self.selectedLineHeight = 2.0 * self.lineHeight + let onePixel: CGFloat = 1.0 / UIScreen.main.scale + lineHeight = 2.0 * onePixel + selectedLineHeight = 2.0 * self.lineHeight } // MARK: Responder handling @@ -318,7 +320,7 @@ open class SkyFloatingLabelTextField: UITextField { @discardableResult override open func becomeFirstResponder() -> Bool { let result = super.becomeFirstResponder() - self.updateControl(true) + updateControl(true) return result } @@ -329,82 +331,82 @@ open class SkyFloatingLabelTextField: UITextField { @discardableResult override open func resignFirstResponder() -> Bool { let result = super.resignFirstResponder() - self.updateControl(true) + updateControl(true) return result } // MARK: - View updates - fileprivate func updateControl(_ animated:Bool = false) { - self.updateColors() - self.updateLineView() - self.updateTitleLabel(animated) + fileprivate func updateControl(_ animated: Bool = false) { + updateColors() + updateLineView() + updateTitleLabel(animated) } fileprivate func updateLineView() { - if let lineView = self.lineView { - lineView.frame = self.lineViewRectForBounds(self.bounds, editing: self.editingOrSelected) + if let lineView = lineView { + lineView.frame = lineViewRectForBounds(bounds, editing: editingOrSelected) } - self.updateLineColor() + updateLineColor() } // MARK: - Color updates /// Update the colors for the control. Override to customize colors. open func updateColors() { - self.updateLineColor() - self.updateTitleColor() - self.updateTextColor() + updateLineColor() + updateTitleColor() + updateTextColor() } fileprivate func updateLineColor() { - if self.hasErrorMessage { - self.lineView.backgroundColor = self.errorColor + if hasErrorMessage { + lineView.backgroundColor = errorColor } else { - self.lineView.backgroundColor = self.editingOrSelected ? self.selectedLineColor : self.lineColor + lineView.backgroundColor = editingOrSelected ? selectedLineColor : lineColor } } fileprivate func updateTitleColor() { - if self.hasErrorMessage { - self.titleLabel.textColor = self.errorColor + if hasErrorMessage { + titleLabel.textColor = errorColor } else { - if self.editingOrSelected || self.isHighlighted { - self.titleLabel.textColor = self.selectedTitleColor + if editingOrSelected || isHighlighted { + titleLabel.textColor = selectedTitleColor } else { - self.titleLabel.textColor = self.titleColor + titleLabel.textColor = titleColor } } } fileprivate func updateTextColor() { - if self.hasErrorMessage { - super.textColor = self.errorColor + if hasErrorMessage { + super.textColor = errorColor } else { - super.textColor = self.cachedTextColor + super.textColor = cachedTextColor } } // MARK: - Title handling - fileprivate func updateTitleLabel(_ animated:Bool = false) { + fileprivate func updateTitleLabel(_ animated: Bool = false) { - var titleText:String? = nil - if self.hasErrorMessage { - titleText = self.titleFormatter(errorMessage!) + var titleText: String? = nil + if hasErrorMessage { + titleText = titleFormatter(errorMessage!) } else { - if self.editingOrSelected { - titleText = self.selectedTitleOrTitlePlaceholder() + if editingOrSelected { + titleText = selectedTitleOrTitlePlaceholder() if titleText == nil { - titleText = self.titleOrPlaceholder() + titleText = titleOrPlaceholder() } } else { - titleText = self.titleOrPlaceholder() + titleText = titleOrPlaceholder() } } - self.titleLabel.text = titleText + titleLabel.text = titleText - self.updateTitleVisibility(animated) + updateTitleVisibility(animated) } fileprivate var _titleVisible = false @@ -412,13 +414,13 @@ open class SkyFloatingLabelTextField: UITextField { /* * Set this value to make the title visible */ - open func setTitleVisible(_ titleVisible:Bool, animated:Bool = false, animationCompletion: ((_ completed: Bool) -> Void)? = nil) { - if(_titleVisible == titleVisible) { + open func setTitleVisible(_ titleVisible: Bool, animated: Bool = false, animationCompletion: ((_ completed: Bool) -> Void)? = nil) { + if _titleVisible == titleVisible { return } _titleVisible = titleVisible - self.updateTitleColor() - self.updateTitleVisibility(animated, completion: animationCompletion) + updateTitleColor() + updateTitleVisibility(animated, completion: animationCompletion) } /** @@ -426,20 +428,20 @@ open class SkyFloatingLabelTextField: UITextField { - returns: True if the title is displayed on the control, false otherwise. */ open func isTitleVisible() -> Bool { - return self.hasText || self.hasErrorMessage || _titleVisible + return hasText || hasErrorMessage || _titleVisible } - fileprivate func updateTitleVisibility(_ animated:Bool = false, completion: ((_ completed: Bool) -> Void)? = nil) { - let alpha:CGFloat = self.isTitleVisible() ? 1.0 : 0.0 - let frame:CGRect = self.titleLabelRectForBounds(self.bounds, editing: self.isTitleVisible()) + fileprivate func updateTitleVisibility(_ animated: Bool = false, completion: ((_ completed: Bool) -> Void)? = nil) { + let alpha: CGFloat = isTitleVisible() ? 1.0 : 0.0 + let frame: CGRect = titleLabelRectForBounds(bounds, editing: isTitleVisible()) let updateBlock = { () -> Void in self.titleLabel.alpha = alpha self.titleLabel.frame = frame } if animated { - let animationOptions:UIViewAnimationOptions = .curveEaseOut; - let duration = self.isTitleVisible() ? titleFadeInDuration : titleFadeOutDuration - self.layoutIfNeeded() + let animationOptions: UIViewAnimationOptions = .curveEaseOut; + let duration = isTitleVisible() ? titleFadeInDuration : titleFadeOutDuration + layoutIfNeeded() UIView.animate(withDuration: duration, delay: 0, options: animationOptions, animations: { () -> Void in updateBlock() }, completion: completion) @@ -458,9 +460,7 @@ open class SkyFloatingLabelTextField: UITextField { */ override open func textRect(forBounds bounds: CGRect) -> CGRect { super.textRect(forBounds: bounds) - let titleHeight = self.titleHeight() - let lineHeight = self.selectedLineHeight - let rect = CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: bounds.size.height - titleHeight - lineHeight) + let rect = CGRect(x: 0, y: titleHeight(), width: bounds.size.width, height: bounds.size.height - titleHeight() - selectedLineHeight) return rect } @@ -470,9 +470,7 @@ open class SkyFloatingLabelTextField: UITextField { - returns: The rectangle that the textfield should render in */ override open func editingRect(forBounds bounds: CGRect) -> CGRect { - let titleHeight = self.titleHeight() - let lineHeight = self.selectedLineHeight - let rect = CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: bounds.size.height - titleHeight - lineHeight) + let rect = CGRect(x: 0, y: titleHeight(), width: bounds.size.width, height: bounds.size.height - titleHeight() - selectedLineHeight) return rect } @@ -482,9 +480,7 @@ open class SkyFloatingLabelTextField: UITextField { - returns: The rectangle that the placeholder should render in */ override open func placeholderRect(forBounds bounds: CGRect) -> CGRect { - let titleHeight = self.titleHeight() - let lineHeight = self.selectedLineHeight - let rect = CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: bounds.size.height - titleHeight - lineHeight) + let rect = CGRect(x: 0, y: titleHeight(), width: bounds.size.width, height: bounds.size.height - titleHeight() - selectedLineHeight) return rect } @@ -496,12 +492,11 @@ open class SkyFloatingLabelTextField: UITextField { - parameter editing: True if the control is selected or highlighted - returns: The rectangle that the title label should render in */ - open func titleLabelRectForBounds(_ bounds:CGRect, editing:Bool) -> CGRect { - let titleHeight = self.titleHeight() + open func titleLabelRectForBounds(_ bounds: CGRect, editing: Bool) -> CGRect { if editing { - return CGRect(x: 0, y: 0, width: bounds.size.width, height: titleHeight) + return CGRect(x: 0, y: 0, width: bounds.size.width, height: titleHeight()) } - return CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: titleHeight) + return CGRect(x: 0, y: titleHeight(), width: bounds.size.width, height: titleHeight()) } /** @@ -510,9 +505,9 @@ open class SkyFloatingLabelTextField: UITextField { - parameter editing: True if the control is selected or highlighted - returns: The rectangle that the line bar should render in */ - open func lineViewRectForBounds(_ bounds:CGRect, editing:Bool) -> CGRect { - let lineHeight:CGFloat = editing ? CGFloat(self.selectedLineHeight) : CGFloat(self.lineHeight) - return CGRect(x: 0, y: bounds.size.height - lineHeight, width: bounds.size.width, height: lineHeight); + open func lineViewRectForBounds(_ bounds: CGRect, editing: Bool) -> CGRect { + let height = editing ? selectedLineHeight : lineHeight + return CGRect(x: 0, y: bounds.size.height - height, width: bounds.size.width, height: height); } /** @@ -520,7 +515,7 @@ open class SkyFloatingLabelTextField: UITextField { -returns: the calculated height of the title label. Override to size the title with a different height */ open func titleHeight() -> CGFloat { - if let titleLabel = self.titleLabel, + if let titleLabel = titleLabel, let font = titleLabel.font { return font.lineHeight } @@ -532,7 +527,7 @@ open class SkyFloatingLabelTextField: UITextField { -returns: the calculated height of the textfield. Override to size the textfield with a different height */ open func textHeight() -> CGFloat { - return self.font!.lineHeight + 7.0 + return font!.lineHeight + 7.0 } // MARK: - Layout @@ -543,20 +538,20 @@ open class SkyFloatingLabelTextField: UITextField { super.prepareForInterfaceBuilder() } - self.borderStyle = .none + borderStyle = .none - self.isSelected = true + isSelected = true _renderingInInterfaceBuilder = true - self.updateControl(false) - self.invalidateIntrinsicContentSize() + updateControl(false) + invalidateIntrinsicContentSize() } /// Invoked by layoutIfNeeded automatically override open func layoutSubviews() { super.layoutSubviews() - self.titleLabel.frame = self.titleLabelRectForBounds(self.bounds, editing: self.isTitleVisible() || _renderingInInterfaceBuilder) - self.lineView.frame = self.lineViewRectForBounds(self.bounds, editing: self.editingOrSelected || _renderingInInterfaceBuilder) + titleLabel.frame = self.titleLabelRectForBounds(bounds, editing: isTitleVisible() || _renderingInInterfaceBuilder) + lineView.frame = self.lineViewRectForBounds(bounds, editing: editingOrSelected || _renderingInInterfaceBuilder) } /** @@ -564,22 +559,22 @@ open class SkyFloatingLabelTextField: UITextField { - returns: the content size to be used for auto layout */ - override open var intrinsicContentSize : CGSize { - return CGSize(width: self.bounds.size.width, height: self.titleHeight() + self.textHeight()) + override open var intrinsicContentSize: CGSize { + return CGSize(width: bounds.size.width, height: titleHeight() + textHeight()) } // MARK: - Helpers fileprivate func titleOrPlaceholder() -> String? { - if let title = self.title ?? self.placeholder { - return self.titleFormatter(title) + if let title = title ?? placeholder { + return titleFormatter(title) } return nil } fileprivate func selectedTitleOrTitlePlaceholder() -> String? { - if let title = self.selectedTitle ?? self.title ?? self.placeholder { - return self.titleFormatter(title) + if let title = selectedTitle ?? title ?? placeholder { + return titleFormatter(title) } return nil } diff --git a/Sources/SkyFloatingLabelTextFieldWithIcon.swift b/Sources/SkyFloatingLabelTextFieldWithIcon.swift index 6e45b98..86c833c 100644 --- a/Sources/SkyFloatingLabelTextFieldWithIcon.swift +++ b/Sources/SkyFloatingLabelTextFieldWithIcon.swift @@ -14,69 +14,69 @@ import UIKit open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { /// A UILabel value that identifies the label used to display the icon - open var iconLabel:UILabel! + open var iconLabel: UILabel! /// A UIFont value that determines the font that the icon is using @IBInspectable - dynamic open var iconFont:UIFont? { + dynamic open var iconFont: UIFont? { didSet { - self.iconLabel?.font = iconFont + iconLabel?.font = iconFont } } /// A String value that determines the text used when displaying the icon @IBInspectable - open var iconText:String? { + open var iconText: String? { didSet { - self.iconLabel?.text = iconText + iconLabel?.text = iconText } } /// A UIColor value that determines the color of the icon in the normal state @IBInspectable - dynamic open var iconColor:UIColor = UIColor.gray { + dynamic open var iconColor: UIColor = UIColor.gray { didSet { - self.updateIconLabelColor() + updateIconLabelColor() } } /// A UIColor value that determines the color of the icon when the control is selected @IBInspectable - dynamic open var selectedIconColor:UIColor = UIColor.gray { + dynamic open var selectedIconColor: UIColor = UIColor.gray { didSet { - self.updateIconLabelColor() + updateIconLabelColor() } } /// A float value that determines the width of the icon @IBInspectable - dynamic open var iconWidth:CGFloat = 20 { + dynamic open var iconWidth: CGFloat = 20 { didSet { - self.updateFrame() + updateFrame() } } /// A float value that determines the left margin of the icon. Use this value to position the icon more precisely horizontally. @IBInspectable - dynamic open var iconMarginLeft:CGFloat = 4 { + dynamic open var iconMarginLeft: CGFloat = 4 { didSet { - self.updateFrame() + updateFrame() } } /// A float value that determines the bottom margin of the icon. Use this value to position the icon more precisely vertically. @IBInspectable - dynamic open var iconMarginBottom:CGFloat = 4 { + dynamic open var iconMarginBottom: CGFloat = 4 { didSet { - self.updateFrame() + updateFrame() } } /// A float value that determines the rotation in degrees of the icon. Use this value to rotate the icon in either direction. @IBInspectable - open var iconRotationDegrees:Double = 0 { + open var iconRotationDegrees: Double = 0 { didSet { - self.iconLabel.transform = CGAffineTransform(rotationAngle: CGFloat(iconRotationDegrees * .pi / 180.0)) + iconLabel.transform = CGAffineTransform(rotationAngle: CGFloat(iconRotationDegrees * .pi / 180.0)) } } @@ -88,7 +88,7 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { */ override public init(frame: CGRect) { super.init(frame: frame) - self.createIconLabel() + createIconLabel() } /** @@ -97,7 +97,7 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { */ required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - self.createIconLabel() + createIconLabel() } // MARK: Creating the icon label @@ -109,9 +109,9 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { iconLabel.textAlignment = .center iconLabel.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin] self.iconLabel = iconLabel - self.addSubview(iconLabel) + addSubview(iconLabel) - self.updateIconLabelColor() + updateIconLabelColor() } // MARK: Handling the icon color @@ -119,14 +119,14 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { /// Update the colors for the control. Override to customize colors. override open func updateColors() { super.updateColors() - self.updateIconLabelColor() + updateIconLabelColor() } fileprivate func updateIconLabelColor() { if self.hasErrorMessage { - self.iconLabel?.textColor = self.errorColor + iconLabel?.textColor = errorColor } else { - self.iconLabel?.textColor = self.editingOrSelected ? self.selectedIconColor : self.iconColor + iconLabel?.textColor = editingOrSelected ? selectedIconColor : iconColor } } @@ -183,16 +183,16 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { /// Invoked by layoutIfNeeded automatically override open func layoutSubviews() { super.layoutSubviews() - self.updateFrame() + updateFrame() } fileprivate func updateFrame() { let textHeight = self.textHeight() - let textWidth:CGFloat = self.bounds.size.width + let textWidth: CGFloat = bounds.size.width if isLTRLanguage { - self.iconLabel.frame = CGRect(x: 0, y: self.bounds.size.height - textHeight - iconMarginBottom, width: iconWidth, height: textHeight) + iconLabel.frame = CGRect(x: 0, y: bounds.size.height - textHeight - iconMarginBottom, width: iconWidth, height: textHeight) } else { - self.iconLabel.frame = CGRect(x: textWidth - iconWidth , y: self.bounds.size.height - textHeight - iconMarginBottom, width: iconWidth, height: textHeight) + iconLabel.frame = CGRect(x: textWidth - iconWidth , y: bounds.size.height - textHeight - iconMarginBottom, width: iconWidth, height: textHeight) } } } diff --git a/Sources/UITextField+fixCaretPosition.swift b/Sources/UITextField+fixCaretPosition.swift index 0bdc5d3..266a6e6 100644 --- a/Sources/UITextField+fixCaretPosition.swift +++ b/Sources/UITextField+fixCaretPosition.swift @@ -15,10 +15,10 @@ extension UITextField { func fixCaretPosition() { // Moving the caret to the correct position by removing the trailing whitespace // http://stackoverflow.com/questions/14220187/uitextfield-has-trailing-whitespace-after-securetextentry-toggle - - let beginning = self.beginningOfDocument - self.selectedTextRange = self.textRange(from: beginning, to: beginning) - let end = self.endOfDocument - self.selectedTextRange = self.textRange(from: end, to: end) + + let beginning = beginningOfDocument + selectedTextRange = textRange(from: beginning, to: beginning) + let end = endOfDocument + selectedTextRange = textRange(from: end, to: end) } } From ae49746c5eb7e038863ba18113debfc7e38b8588 Mon Sep 17 00:00:00 2001 From: Kevin Seidel Date: Wed, 12 Apr 2017 12:00:26 +0200 Subject: [PATCH 2/6] Make title and textHeight computed properties --- .../Example4/IconTextField.swift | 2 +- .../SkyFloatingLabelTextFieldTests.swift | 14 ++--- ...yFloatingLabelTextFieldWithIconTests.swift | 2 +- Sources/SkyFloatingLabelTextField.swift | 56 +++++++++---------- .../SkyFloatingLabelTextFieldWithIcon.swift | 1 - 5 files changed, 34 insertions(+), 41 deletions(-) diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift index 93a0c31..dbfe36a 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift @@ -89,7 +89,7 @@ public class IconTextField: SkyFloatingLabelTextField { override public func layoutSubviews() { super.layoutSubviews() - let textHeight = self.textHeight() + let textHeight = self.textHeight let textWidth:CGFloat = self.bounds.size.width if (isLTRLanguage) { diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift index 7796737..94304ad 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift @@ -577,7 +577,7 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { let rect = floatingLabelTextField.editingRect(forBounds: bounds) // then - XCTAssertEqual(rect.height, boundsHeight - 4 - floatingLabelTextField.titleHeight()) + XCTAssertEqual(rect.height, boundsHeight - 4 - floatingLabelTextField.titleHeight) } // MARK: - control lifecycle events @@ -614,7 +614,7 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { floatingLabelTextField.titleLabel = nil // then - XCTAssertEqual(floatingLabelTextField.titleHeight(), 15) + XCTAssertEqual(floatingLabelTextField.titleHeight, 15) } func test_whenTitleLabelHasFontSet_thenTitleHeightReturnsFontHeight() { @@ -623,7 +623,7 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { floatingLabelTextField.titleLabel.font = font // then - XCTAssertEqual(floatingLabelTextField.titleHeight(), font!.lineHeight) + XCTAssertEqual(floatingLabelTextField.titleHeight, font!.lineHeight) } func test_whenTitleLabelHasFontSetToNil_thenFontSetToDefault() { @@ -642,7 +642,7 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { floatingLabelTextField.font = font // then - XCTAssertEqual(floatingLabelTextField.textHeight(), font!.lineHeight + 7) + XCTAssertEqual(floatingLabelTextField.textHeight, font!.lineHeight + 7) } func test_whenTextFieldHasFontSetToNil_thenFontSetToDefault() { @@ -670,14 +670,14 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { func test_whenIntristicContentSizeInvoked_thenHeightIsTitleHeightAndContentHeightSize() { // given - XCTAssertNotEqual(floatingLabelTextField.titleHeight(), 0) - XCTAssertNotEqual(floatingLabelTextField.textHeight(), 0) + XCTAssertNotEqual(floatingLabelTextField.titleHeight, 0) + XCTAssertNotEqual(floatingLabelTextField.textHeight, 0) // when let size = floatingLabelTextField.intrinsicContentSize // then - XCTAssertEqual(size.height, floatingLabelTextField.titleHeight() + floatingLabelTextField.textHeight()) + XCTAssertEqual(size.height, floatingLabelTextField.titleHeight + floatingLabelTextField.textHeight) } // MARK: - Helpers diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift index e4c84be..b1e3951 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift @@ -71,7 +71,7 @@ class SkyFloatingLabelTextFieldWithIconTests: XCTestCase { floatingLabelTextFieldWithIcon.iconMarginBottom = 5 // then - let expectedHeight = floatingLabelTextFieldWithIcon.bounds.size.height - floatingLabelTextFieldWithIcon.textHeight() - 5 + let expectedHeight = floatingLabelTextFieldWithIcon.bounds.size.height - floatingLabelTextFieldWithIcon.textHeight - 5 XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.frame.origin.y, expectedHeight) } diff --git a/Sources/SkyFloatingLabelTextField.swift b/Sources/SkyFloatingLabelTextField.swift index e53d78c..69ee402 100644 --- a/Sources/SkyFloatingLabelTextField.swift +++ b/Sources/SkyFloatingLabelTextField.swift @@ -137,6 +137,19 @@ open class SkyFloatingLabelTextField: UITextField { // MARK: Properties + /// The computed height of the title label. Override to size the title with a different height + open var titleHeight: CGFloat { + guard let titleLabel = titleLabel, let font = titleLabel.font else { + return 15.0 + } + return font.lineHeight + } + + // The computed height of the text field. Override to size the textfield with a different height + open var textHeight: CGFloat { + return font!.lineHeight + 7.0 + } + /** The formatter to use before displaying content in the title label. This can be the `title`, `selectedTitle` or the `errorMessage`. The default implementation converts the text to uppercase. @@ -460,7 +473,7 @@ open class SkyFloatingLabelTextField: UITextField { */ override open func textRect(forBounds bounds: CGRect) -> CGRect { super.textRect(forBounds: bounds) - let rect = CGRect(x: 0, y: titleHeight(), width: bounds.size.width, height: bounds.size.height - titleHeight() - selectedLineHeight) + let rect = CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: bounds.size.height - titleHeight - selectedLineHeight) return rect } @@ -470,7 +483,7 @@ open class SkyFloatingLabelTextField: UITextField { - returns: The rectangle that the textfield should render in */ override open func editingRect(forBounds bounds: CGRect) -> CGRect { - let rect = CGRect(x: 0, y: titleHeight(), width: bounds.size.width, height: bounds.size.height - titleHeight() - selectedLineHeight) + let rect = CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: bounds.size.height - titleHeight - selectedLineHeight) return rect } @@ -480,7 +493,7 @@ open class SkyFloatingLabelTextField: UITextField { - returns: The rectangle that the placeholder should render in */ override open func placeholderRect(forBounds bounds: CGRect) -> CGRect { - let rect = CGRect(x: 0, y: titleHeight(), width: bounds.size.width, height: bounds.size.height - titleHeight() - selectedLineHeight) + let rect = CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: bounds.size.height - titleHeight - selectedLineHeight) return rect } @@ -494,9 +507,9 @@ open class SkyFloatingLabelTextField: UITextField { */ open func titleLabelRectForBounds(_ bounds: CGRect, editing: Bool) -> CGRect { if editing { - return CGRect(x: 0, y: 0, width: bounds.size.width, height: titleHeight()) + return CGRect(x: 0, y: 0, width: bounds.size.width, height: titleHeight) } - return CGRect(x: 0, y: titleHeight(), width: bounds.size.width, height: titleHeight()) + return CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: titleHeight) } /** @@ -510,25 +523,6 @@ open class SkyFloatingLabelTextField: UITextField { return CGRect(x: 0, y: bounds.size.height - height, width: bounds.size.width, height: height); } - /** - Calculate the height of the title label. - -returns: the calculated height of the title label. Override to size the title with a different height - */ - open func titleHeight() -> CGFloat { - if let titleLabel = titleLabel, - let font = titleLabel.font { - return font.lineHeight - } - return 15.0 - } - - /** - Calcualte the height of the textfield. - -returns: the calculated height of the textfield. Override to size the textfield with a different height - */ - open func textHeight() -> CGFloat { - return font!.lineHeight + 7.0 - } // MARK: - Layout @@ -560,22 +554,22 @@ open class SkyFloatingLabelTextField: UITextField { - returns: the content size to be used for auto layout */ override open var intrinsicContentSize: CGSize { - return CGSize(width: bounds.size.width, height: titleHeight() + textHeight()) + return CGSize(width: bounds.size.width, height: titleHeight + textHeight) } // MARK: - Helpers fileprivate func titleOrPlaceholder() -> String? { - if let title = title ?? placeholder { - return titleFormatter(title) + guard let title = title ?? placeholder else { + return nil } - return nil + return titleFormatter(title) } fileprivate func selectedTitleOrTitlePlaceholder() -> String? { - if let title = selectedTitle ?? title ?? placeholder { - return titleFormatter(title) + guard let title = selectedTitle ?? title ?? placeholder else { + return nil } - return nil + return titleFormatter(title) } } diff --git a/Sources/SkyFloatingLabelTextFieldWithIcon.swift b/Sources/SkyFloatingLabelTextFieldWithIcon.swift index 86c833c..c9ae40e 100644 --- a/Sources/SkyFloatingLabelTextFieldWithIcon.swift +++ b/Sources/SkyFloatingLabelTextFieldWithIcon.swift @@ -187,7 +187,6 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { } fileprivate func updateFrame() { - let textHeight = self.textHeight() let textWidth: CGFloat = bounds.size.width if isLTRLanguage { iconLabel.frame = CGRect(x: 0, y: bounds.size.height - textHeight - iconMarginBottom, width: iconWidth, height: textHeight) From 09d1056e2cc05f598c07841dc38d5daf585311b2 Mon Sep 17 00:00:00 2001 From: Kevin Seidel Date: Thu, 13 Apr 2017 09:46:38 +0200 Subject: [PATCH 3/6] Add swiftlint Added swiftlint build phase and fixed errors and warnings generated by swiftlint --- .swiftlint.yml | 7 + .../project.pbxproj | 18 + .../AppDelegate.swift | 95 ++-- .../ShowcaseExampleViewController.swift | 243 ++++++---- .../Example1/SettingTextsViewController.swift | 68 ++- .../CustomizingColorsViewController.swift | 100 ++-- .../Example3/SubclassingViewController.swift | 49 +- .../Example3/ThemedTextField.swift | 42 +- .../Example4/CustomLayoutViewController.swift | 41 +- .../Example4/IconTextField.swift | 79 +-- .../Example4b/AppearanceViewController.swift | 33 +- .../DelegateMethodsViewController.swift | 82 ++-- .../ViewController.swift | 13 +- ...loatingLabelTextFieldAppearanceTests.swift | 43 +- .../SkyFloatingLabelTextFieldTests.swift | 458 +++++++++--------- ...yFloatingLabelTextFieldWithIconTests.swift | 120 ++--- Sources/SkyFloatingLabelTextField.swift | 13 +- .../SkyFloatingLabelTextFieldWithIcon.swift | 44 +- 18 files changed, 879 insertions(+), 669 deletions(-) create mode 100644 .swiftlint.yml diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 0000000..02984e2 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,7 @@ +disabled_rules: +opt_in_rules: +included: + - Sources + - SkyFloatingLabelTextField +excluded: + diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextField.xcodeproj/project.pbxproj b/SkyFloatingLabelTextField/SkyFloatingLabelTextField.xcodeproj/project.pbxproj index 88f231c..f5cd01b 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextField.xcodeproj/project.pbxproj +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextField.xcodeproj/project.pbxproj @@ -281,6 +281,7 @@ F56289141C3BE3A20082D9A6 /* Frameworks */, F56289151C3BE3A20082D9A6 /* Headers */, F56289161C3BE3A20082D9A6 /* Resources */, + 0AA2E1E11E9F54E0007B6FEC /* Swiftlint */, ); buildRules = ( ); @@ -386,6 +387,23 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 0AA2E1E11E9F54E0007B6FEC /* Swiftlint */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = Swiftlint; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ F547D4A81C3BEA8F0075A0C2 /* Sources */ = { isa = PBXSourcesBuildPhase; diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/AppDelegate.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/AppDelegate.swift index f8b8157..50064a8 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/AppDelegate.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/AppDelegate.swift @@ -1,10 +1,15 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. import UIKit @@ -13,80 +18,72 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? + ) -> Bool { - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - // MARK: - Appearance - + if #available(iOS 9.0, *) { - + // Apply styles for text fields contained in AppearanceViewController - let styles = SkyFloatingLabelTextField.appearance(whenContainedInInstancesOf: [AppearanceViewController.self]) - + let styles = SkyFloatingLabelTextField.appearance( + whenContainedInInstancesOf: [AppearanceViewController.self] + ) + // Text-, placeholder- and tintcolor - styles.textColor = UIColor.brown - styles.tintColor = UIColor.brown - styles.placeholderColor = UIColor.darkGray - styles.selectedTitleColor = UIColor.orange - styles.errorColor = UIColor.purple - + styles.textColor = .brown + styles.tintColor = .brown + styles.placeholderColor = .darkGray + styles.selectedTitleColor = .orange + styles.errorColor = .purple + // Fonts - styles.font = UIFont.systemFont(ofSize: 14, weight: 1.0) - styles.placeholderFont = UIFont.systemFont(ofSize: 14, weight: 0.1) - + styles.font = .systemFont(ofSize: 14, weight: 1.0) + styles.placeholderFont = .systemFont(ofSize: 14, weight: 0.1) + // Line styles.lineHeight = 2 - styles.lineColor = UIColor.brown - + styles.lineColor = .brown + // Selected line styles.selectedLineHeight = 3 - styles.selectedLineColor = UIColor.orange + styles.selectedLineColor = .orange } - + // MARK: - Icon appearance - + if #available(iOS 9.0, *) { - + // Apply icon styles - let iconStyles = SkyFloatingLabelTextFieldWithIcon.appearance(whenContainedInInstancesOf: [AppearanceViewController.self]) - + let iconStyles = SkyFloatingLabelTextFieldWithIcon.appearance( + whenContainedInInstancesOf: [AppearanceViewController.self] + ) + // Icon colors - iconStyles.iconColor = UIColor.brown - iconStyles.selectedIconColor = UIColor.orange - + iconStyles.iconColor = .brown + iconStyles.selectedIconColor = .orange + // Icon font iconStyles.iconFont = UIFont(name: "FontAwesome", size: 15) - + // Icon margins iconStyles.iconMarginLeft = 5 iconStyles.iconMarginBottom = 5 } - - return true - } - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. + return true } - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } + func applicationWillResignActive(_ application: UIApplication) { } - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - } + func applicationDidEnterBackground(_ application: UIApplication) { } - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } + func applicationWillEnterForeground(_ application: UIApplication) { } - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } + func applicationDidBecomeActive(_ application: UIApplication) { } + func applicationWillTerminate(_ application: UIApplication) { } } - diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example0/ShowcaseExampleViewController.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example0/ShowcaseExampleViewController.swift index c636680..4ff3663 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example0/ShowcaseExampleViewController.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example0/ShowcaseExampleViewController.swift @@ -1,10 +1,15 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions and +// limitations under the License. import UIKit @@ -18,132 +23,178 @@ class ShowcaseExampleViewController: UIViewController, UITextFieldDelegate { @IBOutlet weak var nameField: SkyFloatingLabelTextField! @IBOutlet weak var emailField: SkyFloatingLabelTextField! @IBOutlet weak var submitButton: UIButton! - - var textFields : [SkyFloatingLabelTextField]! - + + var textFields: [SkyFloatingLabelTextField]! + let lightGreyColor = UIColor(red: 197/255, green: 205/255, blue: 205/255, alpha: 1.0) let darkGreyColor = UIColor(red: 52/255, green: 42/255, blue: 61/255, alpha: 1.0) let overcastBlueColor = UIColor(red: 0, green: 187/255, blue: 204/255, alpha: 1.0) override func viewDidLoad() { super.viewDidLoad() - + textFields = [arrivalCityField, departureCityField, titleField, nameField, emailField] - self.setupThemeColors() - - self.departureCityField.becomeFirstResponder() + setupButton() + setupCities() + setupUser() + + for textField in textFields { + textField.delegate = self + } + + departureCityField.becomeFirstResponder() } - + // MARK: - Creating the form elements - - func setupThemeColors() { - self.submitButton.layer.borderColor = darkGreyColor.cgColor - self.submitButton.layer.borderWidth = 1 - self.submitButton.layer.cornerRadius = 5 - self.submitButton.setTitleColor(overcastBlueColor, for: .highlighted) - - self.applySkyscannerThemeWithIcon(textField: self.departureCityField) - self.departureCityField.iconText = "\u{f072}" // plane icon as per https://fortawesome.github.io/Font-Awesome/cheatsheet/ - self.departureCityField.placeholder = NSLocalizedString("Departure City", tableName: "SkyFloatingLabelTextField", comment: "placeholder for the departure city field") - self.departureCityField.selectedTitle = NSLocalizedString("Departure City", tableName: "SkyFloatingLabelTextField", comment: "title for the departure city field") - self.departureCityField.title = NSLocalizedString("Departure City", tableName: "SkyFloatingLabelTextField", comment: "title for the departure city field") - - self.applySkyscannerThemeWithIcon(textField: self.arrivalCityField) + + func setupButton() { + submitButton.layer.borderColor = darkGreyColor.cgColor + submitButton.layer.borderWidth = 1 + submitButton.layer.cornerRadius = 5 + submitButton.setTitleColor(overcastBlueColor, for: .highlighted) + } + + func setupCities() { + + applySkyscannerThemeWithIcon(textField: self.departureCityField) + + // plane icon as per https://fortawesome.github.io/Font-Awesome/cheatsheet/ + departureCityField.iconText = "\u{f072}" + departureCityField.placeholder = + NSLocalizedString("Departure City", + tableName: "SkyFloatingLabelTextField", + comment: "placeholder for the departure city field") + departureCityField.selectedTitle = + NSLocalizedString("Departure City", + tableName: "SkyFloatingLabelTextField", + comment: "title for the departure city field") + departureCityField.title = + NSLocalizedString("Departure City", + tableName: "SkyFloatingLabelTextField", + comment: "title for the departure city field") + + applySkyscannerThemeWithIcon(textField: arrivalCityField) + if isLTRLanguage { - self.arrivalCityField.iconRotationDegrees = 90 + arrivalCityField.iconRotationDegrees = 90 } else { // In RTL languages the plane should point to the other side - self.arrivalCityField.iconRotationDegrees = 180 - self.departureCityField.iconRotationDegrees = 270 - } - self.arrivalCityField.iconText = "\u{f072}" - - self.arrivalCityField.placeholder = NSLocalizedString("Arrival City", tableName: "SkyFloatingLabelTextField", comment: "placeholder for the arrival city field") - self.arrivalCityField.selectedTitle = NSLocalizedString("Arrival City", tableName: "SkyFloatingLabelTextField", comment: "title for the arrival city field") - self.arrivalCityField.title = NSLocalizedString("Arrival City", tableName: "SkyFloatingLabelTextField", comment: "title for the arrival city field") - - self.titleField.placeholder = NSLocalizedString("Title", tableName: "SkyFloatingLabelTextField", comment: "placeholder for person title field") - self.titleField.selectedTitle = NSLocalizedString("Title", tableName: "SkyFloatingLabelTextField", comment: "selected title for person title field") - self.titleField.title = NSLocalizedString("Title", tableName: "SkyFloatingLabelTextField", comment: "title for person title field") - - self.nameField.placeholder = NSLocalizedString("Name", tableName: "SkyFloatingLabelTextField", comment: "placeholder for traveler name field") - self.nameField.selectedTitle = NSLocalizedString("Name", tableName: "SkyFloatingLabelTextField", comment: "selected title for traveler name field") - self.nameField.title = NSLocalizedString("Name", tableName: "SkyFloatingLabelTextField", comment: "title for traveler name field") - - self.emailField.placeholder = NSLocalizedString("Email", tableName: "SkyFloatingLabelTextField", comment: "placeholder for Email field") - self.emailField.selectedTitle = NSLocalizedString("Email", tableName: "SkyFloatingLabelTextField", comment: "selected title for Email field") - self.emailField.title = NSLocalizedString("Email", tableName: "SkyFloatingLabelTextField", comment: "title for Email field") - - self.applySkyscannerTheme(textField: self.titleField) - self.applySkyscannerTheme(textField: self.nameField) - self.applySkyscannerTheme(textField: self.emailField) - - for textField in textFields { - textField.delegate = self + arrivalCityField.iconRotationDegrees = 180 + departureCityField.iconRotationDegrees = 270 } + + arrivalCityField.iconText = "\u{f072}" + + arrivalCityField.placeholder = NSLocalizedString("Arrival City", + tableName: "SkyFloatingLabelTextField", + comment: "placeholder for the arrival city field") + arrivalCityField.selectedTitle = NSLocalizedString("Arrival City", + tableName: "SkyFloatingLabelTextField", + comment: "title for the arrival city field") + arrivalCityField.title = NSLocalizedString("Arrival City", + tableName: "SkyFloatingLabelTextField", + comment: "title for the arrival city field") + } + + func setupUser() { + + titleField.placeholder = NSLocalizedString("Title", + tableName: "SkyFloatingLabelTextField", + comment: "placeholder for person title field") + titleField.selectedTitle = NSLocalizedString("Title", + tableName: "SkyFloatingLabelTextField", + comment: "selected title for person title field") + titleField.title = NSLocalizedString("Title", + tableName: "SkyFloatingLabelTextField", + comment: "title for person title field") + + nameField.placeholder = NSLocalizedString("Name", + tableName: "SkyFloatingLabelTextField", + comment: "placeholder for traveler name field") + nameField.selectedTitle = NSLocalizedString("Name", + tableName: "SkyFloatingLabelTextField", + comment: "selected title for traveler name field") + nameField.title = NSLocalizedString("Name", + tableName: "SkyFloatingLabelTextField", + comment: "title for traveler name field") + + emailField.placeholder = NSLocalizedString("Email", + tableName: "SkyFloatingLabelTextField", + comment: "placeholder for Email field") + emailField.selectedTitle = NSLocalizedString("Email", + tableName: "SkyFloatingLabelTextField", + comment: "selected title for Email field") + emailField.title = NSLocalizedString("Email", + tableName: "SkyFloatingLabelTextField", + comment: "title for Email field") + + applySkyscannerTheme(textField: titleField) + applySkyscannerTheme(textField: nameField) + applySkyscannerTheme(textField: emailField) + } - + // MARK: - Styling the text fields to the Skyscanner theme - + func applySkyscannerThemeWithIcon(textField: SkyFloatingLabelTextFieldWithIcon) { self.applySkyscannerTheme(textField: textField) - + textField.iconColor = lightGreyColor textField.selectedIconColor = overcastBlueColor textField.iconFont = UIFont(name: "FontAwesome", size: 15) } - + func applySkyscannerTheme(textField: SkyFloatingLabelTextField) { - + textField.tintColor = overcastBlueColor - + textField.textColor = darkGreyColor textField.lineColor = lightGreyColor - + textField.selectedTitleColor = overcastBlueColor textField.selectedLineColor = overcastBlueColor - + // Set custom fonts for the title, placeholder and textfield labels textField.titleLabel.font = UIFont(name: "AppleSDGothicNeo-Regular", size: 12) textField.placeholderFont = UIFont(name: "AppleSDGothicNeo-Light", size: 18) textField.font = UIFont(name: "AppleSDGothicNeo-Regular", size: 18) } - + // MARK: - Validating the fields when "submit" is pressed - + var isSubmitButtonPressed = false - + var showingTitleInProgress = false - + @IBAction func submitButtonDown(_ sender: AnyObject) { self.isSubmitButtonPressed = true - - for textField in textFields { - if !textField.hasText { - self.showingTitleInProgress = true - textField.setTitleVisible(true, animated: true, animationCompletion: self.showingTitleInAnimationComplete) + + for textField in textFields where !textField.hasText { + showingTitleInProgress = true + textField.setTitleVisible(true, + animated: true, + animationCompletion: showingTitleInAnimationComplete) textField.isHighlighted = true - } } } - + @IBAction func submitButtonTouchUpInside(_ sender: AnyObject) { - self.isSubmitButtonPressed = false - if(!self.showingTitleInProgress) { - self.hideTitleVisibleFromFields() + isSubmitButtonPressed = false + if !showingTitleInProgress { + hideTitleVisibleFromFields() } } - + func showingTitleInAnimationComplete(_ completed: Bool) { // If a field is not filled out, display the highlighted title for 0.3 seco DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { self.showingTitleInProgress = false - if(!self.isSubmitButtonPressed) { + if !self.isSubmitButtonPressed { self.hideTitleVisibleFromFields() } } } - + func hideTitleVisibleFromFields() { for textField in textFields { @@ -152,15 +203,15 @@ class ShowcaseExampleViewController: UIViewController, UITextFieldDelegate { } } - + // MARK: - Delegate - + func textFieldShouldReturn(_ textField: UITextField) -> Bool { // Validate the email field - if (textField == self.emailField) { + if textField == emailField { validateEmailField() } - + // When pressing return, move to the next field let nextTag = textField.tag + 1 if let nextResponder = textField.superview?.viewWithTag(nextTag) as UIResponder! { @@ -170,26 +221,28 @@ class ShowcaseExampleViewController: UIViewController, UITextFieldDelegate { } return false } - + @IBAction func validateEmailField() { validateEmailTextFieldWithText(email: emailField.text) } - + func validateEmailTextFieldWithText(email: String?) { - if let email = email { - if(email.characters.count == 0) { - self.emailField.errorMessage = nil - } - else if validateEmail(email) == false { - self.emailField.errorMessage = NSLocalizedString("Email not valid", tableName: "SkyFloatingLabelTextField", comment: " ") - } else { - self.emailField.errorMessage = nil - } + guard let email = email else { + emailField.errorMessage = nil + return + } + + if email.characters.count == 0 { + emailField.errorMessage = nil + } else if !validateEmail(email) { + emailField.errorMessage = NSLocalizedString("Email not valid", + tableName: "SkyFloatingLabelTextField", + comment: " ") } else { - self.emailField.errorMessage = nil + emailField.errorMessage = nil } } - + // MARK: - validation func validateEmail(_ candidate: String) -> Bool { @@ -197,7 +250,7 @@ class ShowcaseExampleViewController: UIViewController, UITextFieldDelegate { // NOTE: validating email addresses with regex is usually not the best idea. // This implementation is for demonstration purposes only and is not recommended for production use. // Regex source and more information here: http://emailregex.com - + let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}" return NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: candidate) } diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example1/SettingTextsViewController.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example1/SettingTextsViewController.swift index dd0cc1b..50c5673 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example1/SettingTextsViewController.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example1/SettingTextsViewController.swift @@ -1,64 +1,82 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. import UIKit class SettingTextsViewController: UIViewController { - @IBOutlet var textField:SkyFloatingLabelTextField? - - @IBOutlet var addErrorButton:UIButton? - + @IBOutlet var textField: SkyFloatingLabelTextField? + + @IBOutlet var addErrorButton: UIButton? + @IBAction func addError() { - if(self.addErrorButton?.title(for: .normal) == NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title")) { - self.textField?.errorMessage = NSLocalizedString("error message", tableName: "SkyFloatingLabelTextField", comment: "error message") - self.addErrorButton?.setTitle(NSLocalizedString("Clear error", tableName: "SkyFloatingLabelTextField", comment: "clear errors button title"), for: .normal) + let localizedAddError = NSLocalizedString( + "Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title" + ) + if addErrorButton?.title(for: .normal) == localizedAddError { + textField?.errorMessage = NSLocalizedString("error message", + tableName: "SkyFloatingLabelTextField", + comment: "error message") + addErrorButton?.setTitle( + NSLocalizedString("Clear error", + tableName: "SkyFloatingLabelTextField", + comment: "clear errors button title"), for: .normal) } else { - self.textField?.errorMessage = "" - self.addErrorButton?.setTitle(NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title"), for: .normal) + textField?.errorMessage = "" + addErrorButton?.setTitle(NSLocalizedString("Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title"), for: .normal) } } - + @IBAction func resignTextField() { - self.textField?.resignFirstResponder() + textField?.resignFirstResponder() } - - @IBAction func selectedTitleChanged(_ segmentedControl:UISegmentedControl) { + + @IBAction func selectedTitleChanged(_ segmentedControl: UISegmentedControl) { switch segmentedControl.selectedSegmentIndex { case 0: - self.textField?.selectedTitle = nil + textField?.selectedTitle = nil case 1: - self.textField?.selectedTitle = "Selected title" + textField?.selectedTitle = "Selected title" default: break } } - @IBAction func titleChanged(_ segmentedControl:UISegmentedControl) { + @IBAction func titleChanged(_ segmentedControl: UISegmentedControl) { switch segmentedControl.selectedSegmentIndex { case 0: - self.textField?.title = nil + textField?.title = nil case 1: - self.textField?.title = "Deselected title" + textField?.title = "Deselected title" default: break } } - - @IBAction func placeholderChanged(_ segmentedControl:UISegmentedControl) { + + @IBAction func placeholderChanged(_ segmentedControl: UISegmentedControl) { switch segmentedControl.selectedSegmentIndex { case 0: - self.textField?.placeholder = nil + textField?.placeholder = nil case 1: - self.textField?.placeholder = NSLocalizedString("Placeholder", tableName: "SkyFloatingLabelTextField", comment: "placeholder for field") + textField?.placeholder = NSLocalizedString("Placeholder", + tableName: "SkyFloatingLabelTextField", + comment: "placeholder for field") default: break } } } - diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example2/CustomizingColorsViewController.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example2/CustomizingColorsViewController.swift index 65a0de3..aebab09 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example2/CustomizingColorsViewController.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example2/CustomizingColorsViewController.swift @@ -1,91 +1,113 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under +// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions and +// limitations under the License. import UIKit class CustomizingColorsViewController: UIViewController { - @IBOutlet weak var textField:SkyFloatingLabelTextField? - + @IBOutlet weak var textField: SkyFloatingLabelTextField? + @IBOutlet weak var selectedTitleColorControl: UISegmentedControl? @IBOutlet weak var titleColorControl: UISegmentedControl? @IBOutlet weak var placeholderColorControl: UISegmentedControl? @IBOutlet weak var tintColorControl: UISegmentedControl? @IBOutlet weak var textColorControl: UISegmentedControl? @IBOutlet weak var errorColorControl: UISegmentedControl? - - @IBOutlet var addErrorButton:UIButton? - + + @IBOutlet var addErrorButton: UIButton? + // MARK: - view lifecycle - + override func viewDidLoad() { super.viewDidLoad() - + // NOTE: For emojis to appear properly we need to set the color to white // http://stackoverflow.com/a/38195951 - - let attributes:[String: Any] = [NSForegroundColorAttributeName:UIColor.white] + + let attributes: [String: Any] = [NSForegroundColorAttributeName: UIColor.white] selectedTitleColorControl?.setTitleTextAttributes(attributes, for: .selected) titleColorControl?.setTitleTextAttributes(attributes, for: .selected) textColorControl?.setTitleTextAttributes(attributes, for: .selected) errorColorControl?.setTitleTextAttributes(attributes, for: .selected) tintColorControl?.setTitleTextAttributes(attributes, for: .selected) } - - + // MARK: - user actions - + @IBAction func addError() { - if(self.addErrorButton?.title(for: .normal) == NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title")) { - self.textField?.errorMessage = NSLocalizedString("error message", tableName: "SkyFloatingLabelTextField", comment: "error message") - self.addErrorButton?.setTitle(NSLocalizedString("Clear error", tableName: "SkyFloatingLabelTextField", comment: "clear errors button title"), for: .normal) + let localizedAddError = NSLocalizedString("Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title") + + if self.addErrorButton?.title(for: .normal) == localizedAddError { + textField?.errorMessage = NSLocalizedString("error message", + tableName: "SkyFloatingLabelTextField", + comment: "error message") + addErrorButton?.setTitle( + NSLocalizedString("Clear error", + tableName: "SkyFloatingLabelTextField", + comment: "clear errors button title"), for: .normal) } else { self.textField?.errorMessage = "" - self.addErrorButton?.setTitle(NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title"), for: .normal) + self.addErrorButton?.setTitle( + NSLocalizedString("Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title"), for: .normal) } } - + @IBAction func resignTextField() { - self.textField?.resignFirstResponder() + textField?.resignFirstResponder() } - - @IBAction func titleColorChanged(_ segmentedControl:UISegmentedControl) { - self.textField?.titleColor = self.colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) + + @IBAction func titleColorChanged(_ segmentedControl: UISegmentedControl) { + textField?.titleColor = + colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) } - @IBAction func selectedTitleColorChanged(_ segmentedControl:UISegmentedControl) { - self.textField?.selectedTitleColor = self.colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) + @IBAction func selectedTitleColorChanged(_ segmentedControl: UISegmentedControl) { + textField?.selectedTitleColor = + colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) } - @IBAction func placeholderColorChanged(_ segmentedControl:UISegmentedControl) { - self.textField?.placeholderColor = self.colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) + @IBAction func placeholderColorChanged(_ segmentedControl: UISegmentedControl) { + textField?.placeholderColor = + colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) } - @IBAction func textColorChanged(_ segmentedControl:UISegmentedControl) { - self.textField?.textColor = self.colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) + @IBAction func textColorChanged(_ segmentedControl: UISegmentedControl) { + textField?.textColor = + colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) } - @IBAction func errorColorChanged(_ segmentedControl:UISegmentedControl) { - self.textField?.errorColor = self.colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) + @IBAction func errorColorChanged(_ segmentedControl: UISegmentedControl) { + textField?.errorColor = + colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) } - @IBAction func tintColorChanged(_ segmentedControl:UISegmentedControl) { - self.textField?.tintColor = self.colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) + @IBAction func tintColorChanged(_ segmentedControl: UISegmentedControl) { + textField?.tintColor = + colorForSegmentIndex(segmentIndex: segmentedControl.selectedSegmentIndex) } // MARK: helper - - func colorForSegmentIndex(segmentIndex:Int) -> UIColor { + + func colorForSegmentIndex(segmentIndex: Int) -> UIColor { switch segmentIndex { - case 0: return UIColor.white - case 1: return UIColor.red - case 2: return UIColor.blue - default: return UIColor.black + case 0: return .white + case 1: return .red + case 2: return .blue + default: return .black } } } diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example3/SubclassingViewController.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example3/SubclassingViewController.swift index 65a6ef5..699f50d 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example3/SubclassingViewController.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example3/SubclassingViewController.swift @@ -1,38 +1,55 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. import UIKit class SubclassingViewController: UIViewController { - @IBOutlet var textField:ThemedTextField? - + @IBOutlet var textField: ThemedTextField? + override func viewDidLoad() { super.viewDidLoad() - + // SkyFloatingLabelTextField will inherit it's superview's `tintColor`. self.view.tintColor = UIColor(red: 0.0, green: 221.0/256.0, blue: 238.0/256.0, alpha: 1.0) - self.textField?.placeholder = NSLocalizedString("Placeholder", tableName: "SkyFloatingLabelTextField", comment: "") + textField?.placeholder = NSLocalizedString("Placeholder", tableName: "SkyFloatingLabelTextField", comment: "") } - - @IBOutlet var addErrorButton:UIButton? - + + @IBOutlet var addErrorButton: UIButton? + @IBAction func addError() { - if(self.addErrorButton?.title(for: .normal) == NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title")) { - self.textField?.errorMessage = NSLocalizedString("error message", tableName: "SkyFloatingLabelTextField", comment: "") - self.addErrorButton?.setTitle(NSLocalizedString("Clear error", tableName: "SkyFloatingLabelTextField", comment: "clear errors button title"), for: .normal) + let localizedAddError = NSLocalizedString( + "Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title" + ) + if addErrorButton?.title(for: .normal) == localizedAddError { + textField?.errorMessage = NSLocalizedString("error message", + tableName: "SkyFloatingLabelTextField", + comment: "") + addErrorButton?.setTitle(NSLocalizedString("Clear error", + tableName: "SkyFloatingLabelTextField", + comment: "clear errors button title"), for: .normal) } else { - self.textField?.errorMessage = "" - self.addErrorButton?.setTitle(NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title"), for: .normal) + textField?.errorMessage = "" + addErrorButton?.setTitle( + NSLocalizedString("Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title"), for: .normal) } } - + @IBAction func resignTextField() { - self.textField?.resignFirstResponder() + textField?.resignFirstResponder() } } diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example3/ThemedTextField.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example3/ThemedTextField.swift index ae5a83a..abcdaf6 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example3/ThemedTextField.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example3/ThemedTextField.swift @@ -1,10 +1,15 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. import UIKit @@ -14,27 +19,26 @@ public class ThemedTextField: SkyFloatingLabelTextField { super.init(frame: frame) self.setupTheme() } - + required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.setupTheme() } - + private func setupTheme() { - - let blueColor = UIColor(red: 0.0, green: 221.0/256.0, blue: 238.0/256.0, alpha: 1.0) - let whiteColor = UIColor.white - let errorColor = UIColor.red - - let font = UIFont.systemFont(ofSize: 18.0) - self.font = font - self.placeholderFont = UIFont.italicSystemFont(ofSize: font.pointSize) - - self.errorColor = errorColor - self.textColor = whiteColor - self.selectedLineColor = blueColor - self.lineColor = whiteColor - self.titleColor = whiteColor - self.selectedTitleColor = blueColor + + let blueColor = UIColor(red: 0.0, green: 221.0 / 256.0, blue: 238.0 / 256.0, alpha: 1.0) + + font = .systemFont(ofSize: 18.0) + if let font = font { + placeholderFont = .italicSystemFont(ofSize: font.pointSize) + } + + errorColor = .red + textColor = .white + selectedLineColor = blueColor + lineColor = .white + titleColor = .white + selectedTitleColor = blueColor } } diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/CustomLayoutViewController.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/CustomLayoutViewController.swift index fa34bc4..d46506e 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/CustomLayoutViewController.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/CustomLayoutViewController.swift @@ -1,31 +1,46 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. import UIKit class CustomLayoutViewController: UIViewController { - @IBOutlet var textField:IconTextField? - - @IBOutlet var addErrorButton:UIButton? - + @IBOutlet var textField: IconTextField? + + @IBOutlet var addErrorButton: UIButton? + @IBAction func addError() { - if(self.addErrorButton?.title(for: .normal) == NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title")) { - self.textField?.errorMessage = NSLocalizedString("error message", tableName: "SkyFloatingLabelTextField", comment: "error message") - self.addErrorButton?.setTitle(NSLocalizedString("Clear error", tableName: "SkyFloatingLabelTextField", comment: "clear errors button title"), for: .normal) + let localizedAddError = NSLocalizedString("Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title") + + if addErrorButton?.title(for: .normal) == localizedAddError { + textField?.errorMessage = NSLocalizedString("error message", + tableName: "SkyFloatingLabelTextField", + comment: "error message") + addErrorButton?.setTitle(NSLocalizedString("Clear error", + tableName: "SkyFloatingLabelTextField", + comment: "clear errors button title"), for: .normal) } else { - self.textField?.errorMessage = "" - self.addErrorButton?.setTitle(NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title"), for: .normal) + textField?.errorMessage = "" + addErrorButton?.setTitle(NSLocalizedString("Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title"), for: .normal) } } - + @IBAction func resignTextField() { - self.textField?.resignFirstResponder() + textField?.resignFirstResponder() } } diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift index dbfe36a..3f9681a 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift @@ -1,71 +1,75 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions and +// limitations under the License. import UIKit @IBDesignable public class IconTextField: SkyFloatingLabelTextField { - - public var iconLabel:UILabel! - public var iconWidth:CGFloat = 25.0 - + + public var iconLabel: UILabel! + public var iconWidth: CGFloat = 25.0 + @IBInspectable - public var icon:String? { + public var icon: String? { didSet { - self.iconLabel?.text = icon + iconLabel?.text = icon } } - + // MARK: Initializers - + override public init(frame: CGRect) { super.init(frame: frame) - self.createIconLabel() + createIconLabel() } - + required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - self.createIconLabel() + createIconLabel() } - + // MARK: Creating the icon label - + func createIconLabel() { - let iconLabel = UILabel() + iconLabel = UILabel() iconLabel.backgroundColor = UIColor.clear iconLabel.textAlignment = .center iconLabel.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin] - self.iconLabel = iconLabel - self.addSubview(iconLabel) + addSubview(iconLabel) - self.updateIconLabelColor() + updateIconLabelColor() } // MARK: Handling the icon color - + override public func updateColors() { - super.updateColors() - self.updateIconLabelColor() + updateColors() + updateIconLabelColor() } private func updateIconLabelColor() { - if self.hasErrorMessage { - self.iconLabel?.textColor = self.errorColor + if hasErrorMessage { + iconLabel?.textColor = errorColor } else { - self.iconLabel?.textColor = self.isEditing ? self.selectedLineColor : self.lineColor + iconLabel?.textColor = isEditing ? selectedLineColor : lineColor } } - + // MARK: Custom layout overrides - + override public func textRect(forBounds bounds: CGRect) -> CGRect { var rect = super.textRect(forBounds: bounds) - if (isLTRLanguage) { + if isLTRLanguage { rect.origin.x += iconWidth } else { rect.origin.x = 0 @@ -79,23 +83,28 @@ public class IconTextField: SkyFloatingLabelTextField { rect.size.width -= iconWidth return rect } - + override public func placeholderRect(forBounds bounds: CGRect) -> CGRect { var rect = super.placeholderRect(forBounds: bounds) rect.origin.x += iconWidth rect.size.width -= iconWidth return rect } - + override public func layoutSubviews() { super.layoutSubviews() - let textHeight = self.textHeight - let textWidth:CGFloat = self.bounds.size.width + let textWidth: CGFloat = bounds.size.width - if (isLTRLanguage) { - self.iconLabel.frame = CGRect(x: 0, y: self.bounds.size.height - textHeight, width: iconWidth, height: textHeight) + if isLTRLanguage { + iconLabel.frame = CGRect(x: 0, + y: bounds.size.height - textHeight, + width: iconWidth, + height: textHeight) } else { - self.iconLabel.frame = CGRect(x: textWidth - iconWidth, y: self.bounds.size.height - textHeight, width:iconWidth, height: textHeight) + iconLabel.frame = CGRect(x: textWidth - iconWidth, + y: bounds.size.height - textHeight, + width: iconWidth, + height: textHeight) } } } diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4b/AppearanceViewController.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4b/AppearanceViewController.swift index 14eb16e..fd715a4 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4b/AppearanceViewController.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4b/AppearanceViewController.swift @@ -1,10 +1,15 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. import UIKit @@ -13,23 +18,33 @@ class AppearanceViewController: UIViewController { @IBOutlet weak var label: SkyFloatingLabelTextField! @IBOutlet weak var iconLabel: SkyFloatingLabelTextFieldWithIcon! @IBOutlet weak var addErrorButton: UIButton! - + override func viewDidLoad() { super.viewDidLoad() iconLabel.iconText = "\u{f072}" } - + @IBAction func resignFirstResponder(_ sender: UIButton) { label.resignFirstResponder() } - + @IBAction func addError(_ sender: UIButton) { - if(addErrorButton?.title(for: .normal) == NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title")) { - label.errorMessage = NSLocalizedString("error message", tableName: "SkyFloatingLabelTextField", comment: "error message") - addErrorButton.setTitle(NSLocalizedString("Clear error", tableName: "SkyFloatingLabelTextField", comment: "clear errors button title"), for: .normal) + let localizedAddError = NSLocalizedString("Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title") + if addErrorButton?.title(for: .normal) == localizedAddError { + label.errorMessage = NSLocalizedString("error message", + tableName: "SkyFloatingLabelTextField", + comment: "error message") + addErrorButton.setTitle( + NSLocalizedString("Clear error", + tableName: "SkyFloatingLabelTextField", + comment: "clear errors button title"), for: .normal) } else { label.errorMessage = "" - addErrorButton?.setTitle(NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title"), for: .normal) + addErrorButton?.setTitle(NSLocalizedString("Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title"), for: .normal) } } } diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example5/DelegateMethodsViewController.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example5/DelegateMethodsViewController.swift index fc6306d..11090e1 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example5/DelegateMethodsViewController.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example5/DelegateMethodsViewController.swift @@ -1,42 +1,56 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. import UIKit class DelegateMethodsViewController: UIViewController, UITextFieldDelegate { - @IBOutlet var textField:SkyFloatingLabelTextField? - @IBOutlet var logTextView:UITextView! - + @IBOutlet var textField: SkyFloatingLabelTextField? + @IBOutlet var logTextView: UITextView! + override func viewDidLoad() { super.viewDidLoad() - self.textField?.delegate = self - self.logTextView?.text = "" + textField?.delegate = self + logTextView?.text = "" } - - @IBOutlet var addErrorButton:UIButton? - + + @IBOutlet var addErrorButton: UIButton? + @IBAction func addError() { - if(self.addErrorButton?.title(for: .normal) == NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title")) { - self.textField?.errorMessage = NSLocalizedString("error message", tableName: "SkyFloatingLabelTextField", comment: "error message") - self.addErrorButton?.setTitle(NSLocalizedString("Clear error", tableName: "SkyFloatingLabelTextField", comment: "clear errors button title"), for: .normal) + let localizedAddError = NSLocalizedString("Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title") + if addErrorButton?.title(for: .normal) == localizedAddError { + textField?.errorMessage = NSLocalizedString("error message", + tableName: "SkyFloatingLabelTextField", + comment: "error message") + addErrorButton?.setTitle(NSLocalizedString("Clear error", + tableName: "SkyFloatingLabelTextField", + comment: "clear errors button title"), for: .normal) } else { - self.textField?.errorMessage = "" - self.addErrorButton?.setTitle(NSLocalizedString("Add error", tableName: "SkyFloatingLabelTextField", comment: "add error button title"), for: .normal) + textField?.errorMessage = "" + addErrorButton?.setTitle(NSLocalizedString("Add error", + tableName: "SkyFloatingLabelTextField", + comment: "add error button title"), for: .normal) } } - + @IBAction func resignTextField() { self.textField?.resignFirstResponder() } - - func log(text:String) { + + func log(text: String) { let date = NSDate() let formatter = DateFormatter() formatter.dateFormat = "HH:mm:ss" @@ -44,39 +58,39 @@ class DelegateMethodsViewController: UIViewController, UITextFieldDelegate { logTextView.text = "\(row)\n" + logTextView.text! } - // MARK: - SkyFloatingLabelTextField delegate - + func textFieldDidBeginEditing(_ textField: UITextField) { - self.log(text: "textFieldDidBeginEditing:") + log(text: "textFieldDidBeginEditing:") } - - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - self.log(text: "textField:shouldChangeCharactersInRange:replacementString:") + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, + replacementString string: String) -> Bool { + log(text: "textField:shouldChangeCharactersInRange:replacementString:") return true } - + func textFieldDidEndEditing(_ textField: UITextField) { - self.log(text: "textFieldDidEndEditing:") + log(text: "textFieldDidEndEditing:") } - + func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { - self.log(text: "textFieldShouldBeginEditing:") + log(text: "textFieldShouldBeginEditing:") return true } - + func textFieldShouldClear(_ textField: UITextField) -> Bool { - self.log(text: "textFieldShouldClear:") + log(text: "textFieldShouldClear:") return true } - + func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { - self.log(text: "textFieldShouldEndEditing:") + log(text: "textFieldShouldEndEditing:") return true } - + func textFieldShouldReturn(_ textField: UITextField) -> Bool { - self.log(text: "textFieldShouldReturn") + log(text: "textFieldShouldReturn") return true } } diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/ViewController.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/ViewController.swift index cffddda..24335a2 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/ViewController.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/ViewController.swift @@ -1,10 +1,15 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. import UIKit @@ -12,14 +17,10 @@ class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() - // Dispose of any resources that can be recreated. } - } - diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldAppearanceTests.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldAppearanceTests.swift index 41929fa..ad1d0c5 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldAppearanceTests.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldAppearanceTests.swift @@ -1,60 +1,65 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. import XCTest @testable import SkyFloatingLabelTextField class SkyFloatingLabelTextFieldAppearanceTests: XCTestCase { - + override func setUp() { super.setUp() - + let styles = SkyFloatingLabelTextField.appearance() - + // Text-, placeholder- and tintcolor styles.textColor = UIColor.brown styles.tintColor = UIColor.brown styles.placeholderColor = UIColor.darkGray styles.selectedTitleColor = UIColor.orange styles.errorColor = UIColor.purple - + // Fonts styles.font = UIFont(name: "HelveticaNeue-Bold", size: 14)! styles.placeholderFont = UIFont(name: "HelveticaNeue-Medium", size: 14)! - + // Line styles.lineHeight = 2 styles.lineColor = UIColor.brown - + // Selected line styles.selectedLineHeight = 3 styles.selectedLineColor = UIColor.orange - + // Apply icon styles let iconStyles = SkyFloatingLabelTextFieldWithIcon.appearance() - + // Icon colors iconStyles.iconColor = UIColor.brown iconStyles.selectedIconColor = UIColor.orange - + // Icon font iconStyles.iconFont = UIFont(name: "FontAwesome", size: 15) - + // Icon margins iconStyles.iconMarginLeft = 5 iconStyles.iconMarginBottom = 5 } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } - + func test_ColorAppearances() { let styles = SkyFloatingLabelTextField.appearance() XCTAssertEqual(styles.textColor, UIColor.brown) @@ -63,13 +68,13 @@ class SkyFloatingLabelTextFieldAppearanceTests: XCTestCase { XCTAssertEqual(styles.selectedTitleColor, UIColor.orange) XCTAssertEqual(styles.errorColor, UIColor.purple) } - + func test_FontAppearances() { let styles = SkyFloatingLabelTextField.appearance() XCTAssertEqual(styles.font, UIFont(name: "HelveticaNeue-Bold", size: 14)!) XCTAssertEqual(styles.placeholderFont, UIFont(name: "HelveticaNeue-Medium", size: 14)!) } - + func test_LineAppearances() { let styles = SkyFloatingLabelTextField.appearance() XCTAssertEqual(styles.lineHeight, 2) @@ -77,18 +82,18 @@ class SkyFloatingLabelTextFieldAppearanceTests: XCTestCase { XCTAssertEqual(styles.selectedLineHeight, 3) XCTAssertEqual(styles.selectedLineColor, UIColor.orange) } - + func test_iconColorAppearances() { let iconStyles = SkyFloatingLabelTextFieldWithIcon.appearance() XCTAssertEqual(iconStyles.iconColor, UIColor.brown) XCTAssertEqual(iconStyles.selectedIconColor, UIColor.orange) } - + func test_iconFontAppearance() { let iconStyles = SkyFloatingLabelTextFieldWithIcon.appearance() XCTAssertEqual(iconStyles.iconFont, UIFont(name: "FontAwesome", size: 15)) } - + func test_iconMarginAppearance() { let iconStyles = SkyFloatingLabelTextFieldWithIcon.appearance() XCTAssertEqual(iconStyles.iconMarginLeft, 5) diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift index 94304ad..7f98fd4 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift @@ -1,687 +1,699 @@ // Copyright 2016 Skyscanner Ltd // -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. import UIKit import XCTest @testable import SkyFloatingLabelTextField -class SkyFloatingLabelTextFieldTests: XCTestCase { - +class SkyFloatingLabelTextFieldTests: XCTestCase { // swiftlint:disable:this type_body_length + var floatingLabelTextField: SkyFloatingLabelTextField! let customColor = UIColor(red: 125/255, green: 120/255, blue: 50/255, alpha: 1.0) let textFieldDelegateMock = TextFieldDelegateMock() - + override func setUp() { super.setUp() floatingLabelTextField = SkyFloatingLabelTextField(frame: CGRect(x: 0, y: 0, width: 200, height: 50)) } - + override func tearDown() { super.tearDown() } - - // MARK: - colors - + + // MARK: - colors + func test_whenSettingTextColor_thenTextFieldTextColorIsChangedToThisColor() { // when floatingLabelTextField.textColor = self.customColor - + // then XCTAssertEqual(floatingLabelTextField.textColor, self.customColor) } - + func test_whenSettingPlaceholderColor_thenPlaceholderColorIsChangedToThisColor() { // when floatingLabelTextField.placeholderColor = self.customColor - + // then XCTAssertEqual(floatingLabelTextField.placeholderColor, self.customColor) } - + func test_whenSettingPlaceholderColor_thenAttributedPlaceholderTextIsSet_withColor() { // given let customColor = UIColor.red floatingLabelTextField.placeholder = "test" - var fullRange:NSRange = NSMakeRange(0, floatingLabelTextField.placeholder!.characters.count) - + var fullRange = + NSRange(location: 0, length: floatingLabelTextField.placeholder!.characters.count) + // when floatingLabelTextField.placeholderColor = customColor - + // then - XCTAssertEqual(floatingLabelTextField.attributedPlaceholder!.attribute(NSForegroundColorAttributeName, at: 0, effectiveRange: &fullRange) as? UIColor, customColor) + XCTAssertEqual( + floatingLabelTextField.attributedPlaceholder!.attribute( + NSForegroundColorAttributeName, at: 0, effectiveRange: &fullRange) as? UIColor, customColor) } - + func test_whenSettingTitleColor_thenTitleLabelTextColorIsChangedToThisColor() { // when floatingLabelTextField.titleColor = self.customColor - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.textColor, self.customColor) } - + func test_whenSettingLineColor_thenLineViewBackgroundColorIsChangedToThisColor() { // when floatingLabelTextField.lineColor = self.customColor - + // then XCTAssertEqual(floatingLabelTextField.lineView.backgroundColor, self.customColor) } - + func test_whenSettingErrorColor_withErrorMessageBeingSet_thenTitleLabelTextColorIsChangedToThisColor() { // given floatingLabelTextField.errorMessage = "test" - + // when floatingLabelTextField.errorColor = self.customColor - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.textColor, self.customColor) } - + func test_whenSettingErrorColor_withErrorMessageBeingEmpty_thenTitleLabelTextColorIsNotChangedToThisColor() { // given floatingLabelTextField.errorMessage = "" - + // when floatingLabelTextField.errorColor = self.customColor - + // then XCTAssertNotEqual(floatingLabelTextField.titleLabel.textColor, self.customColor) } - + func test_whenSettingErrorColor_withErrorMessageBeingNil_thenTitleLabelTextColorIsNotChangedToThisColor() { // given floatingLabelTextField.errorMessage = nil - + // when floatingLabelTextField.errorColor = self.customColor - + // then XCTAssertNotEqual(floatingLabelTextField.titleLabel.textColor, self.customColor) } - + func test_whenSettingErrorColor_withErrorMessageBeingSet_thenLineViewBackgroundColorIsChangedToThisColor() { // given floatingLabelTextField.errorMessage = "test" - + // when floatingLabelTextField.errorColor = self.customColor - - + // then XCTAssertEqual(floatingLabelTextField.lineView.backgroundColor, self.customColor) } - + func test_whenSettingSelectedTitleColor_withTextfieldBeingSelected_thenTitleLabelTextColorIsChangedToThisColor() { // given floatingLabelTextField.isSelected = true - + // when floatingLabelTextField.selectedTitleColor = self.customColor - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.textColor, self.customColor) } - + // MARK: - fonts - + func test_whenSettingPlaceholderFont_thenAttributedPlaceholderTextIsSet_withFont() { // given let customFont = UIFont() floatingLabelTextField.placeholder = "test" - var fullRange:NSRange = NSMakeRange(0, floatingLabelTextField.placeholder!.characters.count) - + var fullRange = + NSRange(location: 0, length: floatingLabelTextField.placeholder!.characters.count) + // when floatingLabelTextField.placeholderFont = customFont - + // then - XCTAssertEqual(floatingLabelTextField.attributedPlaceholder!.attribute(NSFontAttributeName, at: 0, effectiveRange: &fullRange) as? UIFont, customFont) + XCTAssertEqual( + floatingLabelTextField.attributedPlaceholder!.attribute( + NSFontAttributeName, at: 0, effectiveRange: &fullRange) as? UIFont, customFont) } - - func test_whenSettingSelectedLineColor_withTextfieldBeingSelected_thenLineViewBackgroundColorIsChangedToThisColor() { + + func test_whenSettingSelectedLineColor_withTextfieldBeingSelected_thenLineViewBackgroundColorIsChangedToThisColor() { // swiftlint:disable:this line_length // given floatingLabelTextField.isSelected = true - + // when floatingLabelTextField.selectedLineColor = self.customColor - + // then XCTAssertEqual(floatingLabelTextField.lineView.backgroundColor, self.customColor) } - - - // MARK: - line height - + + // MARK: - line height + func test_whenInitializingControl_thenLineHeightIsTwoPixelsOnScreen() { // given let onePixel = 1.0 / Double(UIScreen.main.scale) - + // then XCTAssertEqual(Double(floatingLabelTextField.lineHeight), 2.0 * onePixel) } - + func test_whenSettingLineHeight_thenLineViewHeightIsChangedToThisValue() { // when floatingLabelTextField.lineHeight = 3 - + // then XCTAssertEqual(floatingLabelTextField.lineView.frame.size.height, 3) } - + func test_whenInitializingControl_thenSelectedLineHeightIsFourPixelsOnScreen() { // given let onePixel = 1.0 / Double(UIScreen.main.scale) - + // then XCTAssertEqual(Double(floatingLabelTextField.selectedLineHeight), 4.0 * onePixel) } - + func test_whenSettingSelectedLineHeight__withTextFieldBeingSelected_thenLineViewHeightIsChangedToThisValue() { // given floatingLabelTextField.isSelected = true - + // when floatingLabelTextField.selectedLineHeight = 4 - + // then XCTAssertEqual(floatingLabelTextField.lineView.frame.size.height, 4) } - - // MARK: - text + + // MARK: - text func test_hasText_whenTextPropertyIsNotEmpty_thenReturnsTrue() { // given - floatingLabelTextField.text = "hello"; - + floatingLabelTextField.text = "hello" + // then XCTAssertTrue(floatingLabelTextField.hasText) } - + func test_hasText_whenTextPropertyIsEmpty_thenReturnsFalse() { // given - floatingLabelTextField.text = ""; - + floatingLabelTextField.text = "" + // then XCTAssertFalse(floatingLabelTextField.hasText) } - + func test_whenSettingText_withErrorMessagePresent_thenErrorMessageIsNotChanged() { // given floatingLabelTextField.errorMessage = "error" floatingLabelTextField.title = "title" XCTAssertEqual(floatingLabelTextField.titleLabel.text, "ERROR") - + // when floatingLabelTextField.text = "hello!" - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.text, "ERROR") XCTAssertEqual(floatingLabelTextField.errorMessage, "error") } - + func test_whenBecomeFirstResponder_thenErrorMessageIsNotCleared() { // given floatingLabelTextField.errorMessage = "Error" - + // when floatingLabelTextField.becomeFirstResponder() - + // then XCTAssertEqual(floatingLabelTextField.errorMessage, "Error") } - + func test_whenEditingChangedInvoked_thenErrorMessageIsNotCleared() { // given floatingLabelTextField.errorMessage = "Error" - + // when floatingLabelTextField.editingChanged() - + // then XCTAssertEqual(floatingLabelTextField.errorMessage, "Error") } - + func test_whenEditingChangedInvoked_thenDelegateShouldChangeCharactersInRangeIsNotInvoked() { // given floatingLabelTextField.delegate = textFieldDelegateMock floatingLabelTextField.text = "aa" - + // when floatingLabelTextField.editingChanged() - + // then XCTAssertFalse(textFieldDelegateMock.shouldChangeCharactersInRangeInvoked) } - - // MARK: - editingOrSelected - + + // MARK: - editingOrSelected + func test_whenSettingSelected_toTrue_thenEditingOrSelectedIsTrue() { // given XCTAssertFalse(floatingLabelTextField.isEditing) - + // when floatingLabelTextField.isSelected = true - + // then XCTAssertTrue(floatingLabelTextField.editingOrSelected) } - - // MARK: - highlighted - + + // MARK: - highlighted + func test_whenSettingHighightedFromFalseToTrue_thenHighlightedIsTrue() { // given XCTAssertFalse(floatingLabelTextField.isHighlighted) - + // when floatingLabelTextField.isHighlighted = true - + // then XCTAssertTrue(floatingLabelTextField.isHighlighted) } - - // MARK: - setTitleVisible() - + + // MARK: - setTitleVisible() + func test_whenSettingTitleVisible_toTrue_withoutAnimation_thenTitleAlphaSetToOne() { // given XCTAssertEqual(floatingLabelTextField.titleLabel.alpha, 0.0) - + // when floatingLabelTextField.setTitleVisible(true, animated: false) - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.alpha, 1.0) } - + func test_whenSettingTitleVisible_fromTrueToTrue_withoutAnimation_thenTitleAlphaIsNotChanged() { // given floatingLabelTextField.setTitleVisible(true, animated: false) XCTAssertEqual(floatingLabelTextField.titleLabel.alpha, 1.0) - + // when floatingLabelTextField.setTitleVisible(true, animated: false) - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.alpha, 1.0) } - + func test_whenSettingTitleVisible_toTrue_withAnimation_thenTitleAlphaIsNotChangedImmediately() { // given XCTAssertEqual(floatingLabelTextField.titleLabel.alpha, 0.0) - + // when floatingLabelTextField.setTitleVisible(true, animated: false) - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.alpha, 1.0) } - + func test_whenSettingTitleVisible_toTrue_withAnimation_thenTitleAlphaIsSetToOne_whenCallbackIsInvoked() { // given let expectation = self.expectation(description: "") XCTAssertEqual(floatingLabelTextField.titleLabel.alpha, 0.0) - + // when floatingLabelTextField.setTitleVisible(true, animated: false, animationCompletion: { _ in // then XCTAssertEqual(self.floatingLabelTextField.titleLabel.alpha, 1.0) expectation.fulfill() }) - + self.failOnTimeoutAfterSeconds(5) } - + func test_whenSettingTitleVisible_toTrue_withoutAnimation_thenTitleAlphaIsOne() { // given XCTAssertEqual(floatingLabelTextField.titleLabel.alpha, 0.0) - + // when floatingLabelTextField.setTitleVisible(true, animated: false) - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.alpha, 1.0) } - + func test_whenSettingTitleVisible_toFalse_then_whenAnimationCallbackInvoked_titleIsNotVisible() { // given floatingLabelTextField.setTitleVisible(true, animated: false) let expectation = self.expectation(description: "") - + // when floatingLabelTextField.setTitleVisible(false, animated: true, animationCompletion: { _ in // then XCTAssertEqual(self.floatingLabelTextField.titleLabel.alpha, 0.0) expectation.fulfill() }) - + self.failOnTimeoutAfterSeconds(5) } - + func test_whenSettingTitleVisibleToFalse_withoutAnimation_thenTitleAlphaIsZeroImmediately() { // given floatingLabelTextField.setTitleVisible(true, animated: false) XCTAssertEqual(self.floatingLabelTextField.titleLabel.alpha, 1.0) - + // when floatingLabelTextField.setTitleVisible(false, animated: false) - + // then XCTAssertEqual(self.floatingLabelTextField.titleLabel.alpha, 0.0) } - - // MARK: - placeholder - + + // MARK: - placeholder + func test_whenPlaceholderIsSet_withSelected_andNoTitleSet_thenTitleLabelTextIsUppercasePlaceholderText() { // given floatingLabelTextField.title = nil floatingLabelTextField.selectedTitle = nil floatingLabelTextField.isSelected = true - + // when floatingLabelTextField.placeholder = "placeholderText" - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.text, "PLACEHOLDERTEXT") } - - // MARK: - selectedTitle - + + // MARK: - selectedTitle + func test_whenTitleAndSelectedTitleAreSet_withControlNotBeingSelected_thenTitleLabelDisplaysUppercaseTitle() { // given floatingLabelTextField.isSelected = false - + // when floatingLabelTextField.title = "title" floatingLabelTextField.selectedTitle = "selectedTitle" - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.text, "TITLE") } - + func test_whenTitleIsSetAndSelectedTitleIsNotSet_withControlBeingSelected_thenTitleLabelDisplaysUppercaseTitle() { // given floatingLabelTextField.isSelected = true - + // when floatingLabelTextField.title = "title" floatingLabelTextField.selectedTitle = nil - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.text, "TITLE") } - + func test_whenTitleAndSelectedTitleAreSet_withControlBeingSelected_thenTitleLabelDisplaysUppercaseSelectedTitle() { // given floatingLabelTextField.isSelected = true - + // when floatingLabelTextField.title = "title" floatingLabelTextField.selectedTitle = "selectedTitle" - + // then XCTAssertEqual(floatingLabelTextField.titleLabel.text, "SELECTEDTITLE") } - + // MARK: - Responder handling - + func test_whenBecomeFirstResponderInvoked_thenUpdateColorsInvoked() { // given let floatingLabelTextFieldSpy = SkyFloatingLabelTextFieldSpy() - + // when floatingLabelTextFieldSpy.becomeFirstResponder() - + // then XCTAssertTrue(floatingLabelTextFieldSpy.updateColorsInvoked) } - + func test_whenResignFirstResponderInvoked_thenUpdateColorsInvoked() { // given let floatingLabelTextFieldSpy = SkyFloatingLabelTextFieldSpy() - + // when floatingLabelTextFieldSpy.resignFirstResponder() - + // then XCTAssertTrue(floatingLabelTextFieldSpy.updateColorsInvoked) } - - // MARK: - init - + + // MARK: - init + func test_whenIntiializingWithCoder_thenTextfieldUIElementsAreCreated() { // given let data = NSMutableData() let archiver = NSKeyedArchiver(forWritingWith: data) archiver.finishEncoding() let coder = NSKeyedUnarchiver(forReadingWith: data as Data) - + // when floatingLabelTextField = SkyFloatingLabelTextField(coder: coder) - + // then XCTAssertNotNil(floatingLabelTextField.titleLabel) XCTAssertNotNil(floatingLabelTextField.lineView) } - + // MARK: - Textfield delegate methods - + // MARK: textFieldShouldBeginEditing - + func test_whenTextFieldShouldBeginEditingInvoked_withNonNilDelegate_thenInvokesDelegate() { // given floatingLabelTextField.delegate = textFieldDelegateMock - + // when let result = floatingLabelTextField.delegate!.textFieldShouldBeginEditing!(floatingLabelTextField) - + // then XCTAssertFalse(result) XCTAssertTrue(textFieldDelegateMock.textFieldShouldBeginEditingInvoked) } // MARK: textFieldDidBeginEditing - + func test_whenTextFieldDidBeginEditingInvoked_withNonNilDelegate_thenInvokesDelegate() { // given floatingLabelTextField.delegate = textFieldDelegateMock - + // when floatingLabelTextField.delegate!.textFieldDidBeginEditing!(floatingLabelTextField) - + // then XCTAssertTrue(textFieldDelegateMock.textFieldDidBeginEditingInvoked) } - + // MARK: textFieldShouldEndEditing - + func test_whenTextFieldShouldEndEditingInvoked_withNonNilDelegate_thenInvokesDelegate() { // given floatingLabelTextField.delegate = textFieldDelegateMock - + // when let result = floatingLabelTextField.delegate!.textFieldShouldEndEditing!(floatingLabelTextField) - + // then XCTAssertFalse(result) XCTAssertTrue(textFieldDelegateMock.textFieldShouldEndEditingInvoked) } - + // MARK: textFieldDidEndEditing - + func test_whenTextFieldDidEndEditingInvoked_withNonNilDelegate_thenInvokesDelegate() { // given floatingLabelTextField.delegate = textFieldDelegateMock - + // when floatingLabelTextField.delegate!.textFieldDidEndEditing!(floatingLabelTextField) - + // then XCTAssertTrue(textFieldDelegateMock.textFieldDidEndEditingInvoked) } - + // MARK: textFieldShouldReturn - + func test_whenTextFieldShouldReturnInvoked_withNonNilDelegate_thenInvokesDelegate() { // given floatingLabelTextField.delegate = textFieldDelegateMock - + // when let result = floatingLabelTextField.delegate!.textFieldShouldReturn!(floatingLabelTextField) - + // then XCTAssertFalse(result) XCTAssertTrue(textFieldDelegateMock.textFieldShouldReturnInvoked) } - + // MARK: textFieldShouldClear - + func test_whenTextFieldShouldClearInvoked_withNonNilDelegate_thenInvokesDelegate() { // given floatingLabelTextField.delegate = textFieldDelegateMock - + // when let result = floatingLabelTextField.delegate!.textFieldShouldClear!(floatingLabelTextField) - + // then XCTAssertFalse(result) XCTAssertTrue(textFieldDelegateMock.textFieldShouldClearInvoked) } - + // MARK: shouldChangeCharactersInRange - + func test_whenShouldChangeCharactersInRangeInvoked_withNonNilDelegate_thenInvokesDelegate() { // given floatingLabelTextField.delegate = textFieldDelegateMock - + // when - let result = floatingLabelTextField.delegate!.textField!(floatingLabelTextField, shouldChangeCharactersIn: NSRange(), replacementString:"") - + let result = + floatingLabelTextField.delegate!.textField!(floatingLabelTextField, + shouldChangeCharactersIn: NSRange(), + replacementString:"") + // then XCTAssertFalse(result) XCTAssertTrue(textFieldDelegateMock.shouldChangeCharactersInRangeInvoked) } - - // MARK: - UITextField positioning overrides - + + // MARK: - UITextField positioning overrides + func test_whenInvokingEditingRectForBounds_thenReturnsRectThatSubtractsTitleHeightAndSelectedLineHeight() { // given floatingLabelTextField.selectedLineHeight = 4 - let boundsHeight:CGFloat = 60 + let boundsHeight: CGFloat = 60 let bounds = CGRect(x: 0, y: 0, width: 200, height: boundsHeight) - + // when let rect = floatingLabelTextField.editingRect(forBounds: bounds) - + // then XCTAssertEqual(rect.height, boundsHeight - 4 - floatingLabelTextField.titleHeight) } - - // MARK: - control lifecycle events - + + // MARK: - control lifecycle events + func test_whenLayoutSubviewsInvoked_thenTitleLabelFrameIsUpdated() { // given floatingLabelTextField.titleLabel.frame = CGRect(x: 0, y: 0, width: 0, height: 0) XCTAssertEqual(floatingLabelTextField.titleLabel.frame.height, 0.0) - + // when floatingLabelTextField.layoutSubviews() - + // then XCTAssertNotEqual(floatingLabelTextField.titleLabel.frame.height, 0.0) } - + func test_whenLayoutSubviewsInvoked_thenLineViewFrameIsUpdated() { // given floatingLabelTextField.lineHeight = 2.0 floatingLabelTextField.lineView.frame = CGRect(x: 0, y: 0, width: 0, height: 0) XCTAssertNotEqual(floatingLabelTextField.lineView.frame.height, 2.0) - + // when floatingLabelTextField.layoutSubviews() - + // then XCTAssertEqual(floatingLabelTextField.lineView.frame.height, 2.0) } - + // MARK: titleHeight() - + func test_whenTitleLabelIsNil_thenTitleHeightReturnsFifteen() { // given floatingLabelTextField.titleLabel = nil - + // then XCTAssertEqual(floatingLabelTextField.titleHeight, 15) } - + func test_whenTitleLabelHasFontSet_thenTitleHeightReturnsFontHeight() { // given let font = UIFont(name: "Arial", size: 16) floatingLabelTextField.titleLabel.font = font - + // then XCTAssertEqual(floatingLabelTextField.titleHeight, font!.lineHeight) } - + func test_whenTitleLabelHasFontSetToNil_thenFontSetToDefault() { // when floatingLabelTextField.titleLabel.font = nil - + // then XCTAssertNotNil(floatingLabelTextField.titleLabel.font) } - + // MARK: textHeight() - + func test_whenTextFieldHasFontSet_thenTextHeightReturnsFontHeightPlusSeven() { // given let font = UIFont(name: "Arial", size: 16) floatingLabelTextField.font = font - + // then XCTAssertEqual(floatingLabelTextField.textHeight, font!.lineHeight + 7) } - + func test_whenTextFieldHasFontSetToNil_thenFontSetToDefault() { // when floatingLabelTextField.font = nil - + // then XCTAssertNotNil(floatingLabelTextField.font) } - + // MARK: prepareForInterfaceBuilder() - + func test_whenPrepareForInterfaceBuilderInvoked_thenSelectedSetToTrue() { // given XCTAssertFalse(floatingLabelTextField.isSelected) - + // when floatingLabelTextField.prepareForInterfaceBuilder() - + // then XCTAssertTrue(floatingLabelTextField.isSelected) } - + // MARK: intrinsicContentSize() - + func test_whenIntristicContentSizeInvoked_thenHeightIsTitleHeightAndContentHeightSize() { // given XCTAssertNotEqual(floatingLabelTextField.titleHeight, 0) XCTAssertNotEqual(floatingLabelTextField.textHeight, 0) - + // when let size = floatingLabelTextField.intrinsicContentSize - + // then XCTAssertEqual(size.height, floatingLabelTextField.titleHeight + floatingLabelTextField.textHeight) } - + // MARK: - Helpers - + func failOnTimeoutAfterSeconds(_ timeout: TimeInterval) { self.waitForExpectations(timeout: timeout, handler: {(error: Error?) -> Void in if let error = error { @@ -689,19 +701,20 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { } }) } - - func delay(_ delay:Double, callback:@escaping ()->()) { + + func delay(_ delay: Double, callback: @escaping () -> Void) { + let time = Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) DispatchQueue.main.asyncAfter( - deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: callback) + deadline: DispatchTime.now() + time, execute: callback) } - - class TextFieldDelegateMock:NSObject, UITextFieldDelegate { + + class TextFieldDelegateMock: NSObject, UITextFieldDelegate { var textFieldShouldBeginEditing = false var textFieldShouldEndEditing = false var textFieldShouldReturn = false var textFieldShouldClear = false var shouldChangeCharactersInRange = false - + var textFieldChangedInvoked = false var textFieldShouldBeginEditingInvoked = false var textFieldShouldEndEditingInvoked = false @@ -710,51 +723,52 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { var textFieldShouldReturnInvoked = false var textFieldShouldClearInvoked = false var shouldChangeCharactersInRangeInvoked = false - + func textFieldDidBeginEditing(_ textField: UITextField) { textFieldDidBeginEditingInvoked = true } - + func textFieldChanged(_ textField: UITextField) { textFieldChangedInvoked = true } - + func textFieldDidEndEditing(_ textField: UITextField) { textFieldDidEndEditingInvoked = true } - + func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { textFieldShouldBeginEditingInvoked = true return textFieldShouldBeginEditing } - + func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { textFieldShouldEndEditingInvoked = true return textFieldShouldEndEditing } - + func textFieldShouldReturn(_ textField: UITextField) -> Bool { textFieldShouldReturnInvoked = true return textFieldShouldReturn } - + func textFieldShouldClear(_ textField: UITextField) -> Bool { textFieldShouldClearInvoked = true return textFieldShouldClear } - - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, + replacementString string: String) -> Bool { shouldChangeCharactersInRangeInvoked = true return shouldChangeCharactersInRange } } - + class SkyFloatingLabelTextFieldSpy: SkyFloatingLabelTextField { var updateColorsInvoked = false - + override func updateColors() { updateColorsInvoked = true super.updateColors() } } -} +} // swiftlint:disable:this file_length diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift index b1e3951..b24e90f 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift @@ -13,29 +13,30 @@ class SkyFloatingLabelTextFieldWithIconTests: XCTestCase { var floatingLabelTextFieldWithIcon: SkyFloatingLabelTextFieldWithIcon! let customColor = UIColor(red: 125/255, green: 120/255, blue: 50/255, alpha: 1.0) - + override func setUp() { super.setUp() - floatingLabelTextFieldWithIcon = SkyFloatingLabelTextFieldWithIcon(frame: CGRect(x: 0, y: 0, width: 200, height: 50)) + floatingLabelTextFieldWithIcon = + SkyFloatingLabelTextFieldWithIcon(frame: CGRect(x: 0, y: 0, width: 200, height: 50)) } - + // MARK: - Icons properties - + func test_whenSettingIconFont_thenFontAppliedToIconLabel() { // given let customFont = UIFont() - + // when floatingLabelTextFieldWithIcon.iconFont = customFont - + // then XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.font, customFont) } - + func test_whenSettingIconText_thenTextAppliedToIconLabel() { // when floatingLabelTextFieldWithIcon.iconText = "customIconText" - + // then XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.text, "customIconText") } @@ -43,42 +44,43 @@ class SkyFloatingLabelTextFieldWithIconTests: XCTestCase { func test_whenSettingIconColor_thenColorAppliedToIconLabel() { // when floatingLabelTextFieldWithIcon.iconColor = customColor - + // then XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.textColor, customColor) } - + func test_whenSettingErrorColor_withErrorMessagePresent_thenErrorColorAppliedToIconLabel() { // when floatingLabelTextFieldWithIcon.errorColor = customColor floatingLabelTextFieldWithIcon.errorMessage = "error" - + // then XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.textColor, customColor) } - + func test_whenSettingSelectedIconColor_withTextFieldBeingSelected_thenColorAppliedToIconLabel() { // when floatingLabelTextFieldWithIcon.selectedIconColor = customColor floatingLabelTextFieldWithIcon.isSelected = true - + // then XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.textColor, customColor) } - + func test_whenSettingIconMarginBottom_thenYPositionDecreasedByIconMarginBottom() { // when floatingLabelTextFieldWithIcon.iconMarginBottom = 5 - + // then - let expectedHeight = floatingLabelTextFieldWithIcon.bounds.size.height - floatingLabelTextFieldWithIcon.textHeight - 5 + let height = floatingLabelTextFieldWithIcon.bounds.size.height + let expectedHeight = height - floatingLabelTextFieldWithIcon.textHeight - 5 XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.frame.origin.y, expectedHeight) } - + func test_whenSettingIconRotationDegrees_thenRotationAppliedToIconLabel() { // when floatingLabelTextFieldWithIcon.iconRotationDegrees = 45 - + // then let expectedTransform = CGAffineTransform(rotationAngle: CGFloat(45.0 * .pi / 180.0)) XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.transform.a, expectedTransform.a) @@ -88,139 +90,139 @@ class SkyFloatingLabelTextFieldWithIconTests: XCTestCase { XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.transform.tx, expectedTransform.tx) XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.transform.ty, expectedTransform.ty) } - + // MARK: - Init - + func test_whenIntiializingWithCoder_thenIconLabelIsCreated() { // given let data = NSMutableData() let archiver = NSKeyedArchiver(forWritingWith: data) archiver.finishEncoding() let coder = NSKeyedUnarchiver(forReadingWith: data as Data) - + // when floatingLabelTextFieldWithIcon = SkyFloatingLabelTextFieldWithIcon(coder: coder) - + // then XCTAssertNotNil(floatingLabelTextFieldWithIcon.iconLabel) } - + // MARK: - Layout overrides - + func test_whenInvokingTextRectForBounds_thenReturnsValueWithIconWidthAndMarginSubtracted() { // given - let iconWidth:CGFloat = 10 - let iconMarginLeft:CGFloat = 5 + let iconWidth: CGFloat = 10 + let iconMarginLeft: CGFloat = 5 floatingLabelTextFieldWithIcon.iconWidth = iconWidth floatingLabelTextFieldWithIcon.iconMarginLeft = iconMarginLeft - + // when let rect = floatingLabelTextFieldWithIcon.textRect(forBounds: CGRect(x: 0, y: 0, width: 40, height: 30)) - + // then XCTAssertEqual(rect.origin.x, iconWidth + iconMarginLeft) XCTAssertEqual(rect.size.width, 40 - iconWidth - iconMarginLeft) } - + func test_whenInvokingTextRectForBounds_withNonRTLLanguage_thenRetrunsPositionWithIncoMarginSubtracted() { // given - let iconWidth:CGFloat = 10 - let iconMarginLeft:CGFloat = 5 + let iconWidth: CGFloat = 10 + let iconMarginLeft: CGFloat = 5 floatingLabelTextFieldWithIcon.iconWidth = iconWidth floatingLabelTextFieldWithIcon.iconMarginLeft = iconMarginLeft floatingLabelTextFieldWithIcon.isLTRLanguage = false - + // when let rect = floatingLabelTextFieldWithIcon.textRect(forBounds: CGRect(x: 0, y: 0, width: 40, height: 30)) - + // then XCTAssertEqual(rect.origin.x, -1 * (iconWidth + iconMarginLeft)) XCTAssertEqual(rect.size.width, 40 - iconWidth - iconMarginLeft) } - + func test_whenInvokingEditingRectForBounds_thenReturnsRectThatSubtractsIconWidthAndIconMarginLeft() { // given - let iconWidth:CGFloat = 10 - let iconMarginLeft:CGFloat = 5 + let iconWidth: CGFloat = 10 + let iconMarginLeft: CGFloat = 5 floatingLabelTextFieldWithIcon.iconWidth = iconWidth floatingLabelTextFieldWithIcon.iconMarginLeft = iconMarginLeft - + // when let rect = floatingLabelTextFieldWithIcon.editingRect(forBounds: CGRect(x: 0, y: 0, width: 50, height: 30)) - + // then XCTAssertEqual(rect.origin.x, iconWidth + iconMarginLeft) XCTAssertEqual(rect.size.width, 50 - iconWidth - iconMarginLeft) } - + func test_whenInvokingEditingRectForBounds_withNonRTLLanguage_thenReturnsRectWhereStartPositionIsNotChanged() { // given - let iconWidth:CGFloat = 10 - let iconMarginLeft:CGFloat = 5 + let iconWidth: CGFloat = 10 + let iconMarginLeft: CGFloat = 5 floatingLabelTextFieldWithIcon.iconWidth = iconWidth floatingLabelTextFieldWithIcon.iconMarginLeft = iconMarginLeft floatingLabelTextFieldWithIcon.isLTRLanguage = false - + // when let rect = floatingLabelTextFieldWithIcon.editingRect(forBounds: CGRect(x: 0, y: 0, width: 50, height: 30)) - + // then XCTAssertEqual(rect.origin.x, 0) XCTAssertEqual(rect.size.width, 50 - iconWidth - iconMarginLeft) } - + func test_whenInvokingPlaceholderRectForBounds_thenReturnsValueWithIconWidthAndMarginSubtracted() { // given - let iconWidth:CGFloat = 10 - let iconMarginLeft:CGFloat = 5 + let iconWidth: CGFloat = 10 + let iconMarginLeft: CGFloat = 5 floatingLabelTextFieldWithIcon.iconWidth = iconWidth floatingLabelTextFieldWithIcon.iconMarginLeft = iconMarginLeft - + // when let rect = floatingLabelTextFieldWithIcon.placeholderRect(forBounds: CGRect(x: 0, y: 0, width: 60, height: 30)) - + // then XCTAssertEqual(rect.origin.x, iconWidth + iconMarginLeft) XCTAssertEqual(rect.size.width, 60 - iconWidth - iconMarginLeft) } - + func test_whenInvokingPlaceholderRectForBounds_withNonRTLLanguage_thenReturnsRectWhereStartPositionIsNotChanged() { // given - let iconWidth:CGFloat = 10 - let iconMarginLeft:CGFloat = 5 + let iconWidth: CGFloat = 10 + let iconMarginLeft: CGFloat = 5 floatingLabelTextFieldWithIcon.iconWidth = iconWidth floatingLabelTextFieldWithIcon.iconMarginLeft = iconMarginLeft floatingLabelTextFieldWithIcon.isLTRLanguage = false - + // when let rect = floatingLabelTextFieldWithIcon.placeholderRect(forBounds: CGRect(x: 0, y: 0, width: 60, height: 30)) - + // then XCTAssertEqual(rect.origin.x, 0) XCTAssertEqual(rect.size.width, 60 - iconWidth - iconMarginLeft) } - + func test_whenInvokingLayoutSubviews_thenUpdatesIconLabelFrame() { // given floatingLabelTextFieldWithIcon.iconLabel.frame = CGRect(x: 0, y: 0, width: 0, height: 0) XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.frame.height, 0) - + // when floatingLabelTextFieldWithIcon.layoutSubviews() - + // then XCTAssertNotEqual(floatingLabelTextFieldWithIcon.iconLabel.frame.height, 0) } - + func test_whenInvokingLayoutSubviews_withNonRTLLanguage_thenUpdatesIconLabelFrame() { // given floatingLabelTextFieldWithIcon.iconLabel.frame = CGRect(x: 0, y: 0, width: 0, height: 0) XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.frame.height, 0) floatingLabelTextFieldWithIcon.isLTRLanguage = false - + // when floatingLabelTextFieldWithIcon.layoutSubviews() - + // then XCTAssertNotEqual(floatingLabelTextFieldWithIcon.iconLabel.frame.height, 0) } diff --git a/Sources/SkyFloatingLabelTextField.swift b/Sources/SkyFloatingLabelTextField.swift index 69ee402..6187777 100644 --- a/Sources/SkyFloatingLabelTextField.swift +++ b/Sources/SkyFloatingLabelTextField.swift @@ -52,7 +52,7 @@ open class SkyFloatingLabelTextField: UITextField { } /// A UIColor value that determines text color of the placeholder label - @IBInspectable dynamic open var placeholderColor:UIColor = UIColor.lightGray { + @IBInspectable dynamic open var placeholderColor: UIColor = UIColor.lightGray { didSet { updatePlaceholder() } @@ -279,7 +279,7 @@ open class SkyFloatingLabelTextField: UITextField { addEditingChangedObserver() updateTextAligment() } - + fileprivate func addEditingChangedObserver() { self.addTarget(self, action: #selector(SkyFloatingLabelTextField.editingChanged), for: .editingChanged) } @@ -452,7 +452,7 @@ open class SkyFloatingLabelTextField: UITextField { self.titleLabel.frame = frame } if animated { - let animationOptions: UIViewAnimationOptions = .curveEaseOut; + let animationOptions: UIViewAnimationOptions = .curveEaseOut let duration = isTitleVisible() ? titleFadeInDuration : titleFadeOutDuration layoutIfNeeded() UIView.animate(withDuration: duration, delay: 0, options: animationOptions, animations: { () -> Void in @@ -520,10 +520,9 @@ open class SkyFloatingLabelTextField: UITextField { */ open func lineViewRectForBounds(_ bounds: CGRect, editing: Bool) -> CGRect { let height = editing ? selectedLineHeight : lineHeight - return CGRect(x: 0, y: bounds.size.height - height, width: bounds.size.width, height: height); + return CGRect(x: 0, y: bounds.size.height - height, width: bounds.size.width, height: height) } - // MARK: - Layout /// Invoked when the interface builder renders the control @@ -531,9 +530,9 @@ open class SkyFloatingLabelTextField: UITextField { if #available(iOS 8.0, *) { super.prepareForInterfaceBuilder() } - + borderStyle = .none - + isSelected = true _renderingInInterfaceBuilder = true updateControl(false) diff --git a/Sources/SkyFloatingLabelTextFieldWithIcon.swift b/Sources/SkyFloatingLabelTextFieldWithIcon.swift index c9ae40e..7d48808 100644 --- a/Sources/SkyFloatingLabelTextFieldWithIcon.swift +++ b/Sources/SkyFloatingLabelTextFieldWithIcon.swift @@ -15,7 +15,7 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { /// A UILabel value that identifies the label used to display the icon open var iconLabel: UILabel! - + /// A UIFont value that determines the font that the icon is using @IBInspectable dynamic open var iconFont: UIFont? { @@ -23,7 +23,7 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { iconLabel?.font = iconFont } } - + /// A String value that determines the text used when displaying the icon @IBInspectable open var iconText: String? { @@ -31,7 +31,7 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { iconLabel?.text = iconText } } - + /// A UIColor value that determines the color of the icon in the normal state @IBInspectable dynamic open var iconColor: UIColor = UIColor.gray { @@ -39,7 +39,7 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { updateIconLabelColor() } } - + /// A UIColor value that determines the color of the icon when the control is selected @IBInspectable dynamic open var selectedIconColor: UIColor = UIColor.gray { @@ -47,7 +47,7 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { updateIconLabelColor() } } - + /// A float value that determines the width of the icon @IBInspectable dynamic open var iconWidth: CGFloat = 20 { @@ -55,7 +55,7 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { updateFrame() } } - + /// A float value that determines the left margin of the icon. Use this value to position the icon more precisely horizontally. @IBInspectable dynamic open var iconMarginLeft: CGFloat = 4 { @@ -63,7 +63,7 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { updateFrame() } } - + /// A float value that determines the bottom margin of the icon. Use this value to position the icon more precisely vertically. @IBInspectable dynamic open var iconMarginBottom: CGFloat = 4 { @@ -71,7 +71,7 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { updateFrame() } } - + /// A float value that determines the rotation in degrees of the icon. Use this value to rotate the icon in either direction. @IBInspectable open var iconRotationDegrees: Double = 0 { @@ -79,9 +79,9 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { iconLabel.transform = CGAffineTransform(rotationAngle: CGFloat(iconRotationDegrees * .pi / 180.0)) } } - + // MARK: Initializers - + /** Initializes the control - parameter frame the frame of the control @@ -90,7 +90,7 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { super.init(frame: frame) createIconLabel() } - + /** Intialzies the control by deserializing it - parameter coder the object to deserialize the control from @@ -99,9 +99,9 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { super.init(coder: aDecoder) createIconLabel() } - + // MARK: Creating the icon label - + /// Creates the icon label fileprivate func createIconLabel() { let iconLabel = UILabel() @@ -110,18 +110,18 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { iconLabel.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin] self.iconLabel = iconLabel addSubview(iconLabel) - + updateIconLabelColor() } - + // MARK: Handling the icon color - + /// Update the colors for the control. Override to customize colors. override open func updateColors() { super.updateColors() updateIconLabelColor() } - + fileprivate func updateIconLabelColor() { if self.hasErrorMessage { iconLabel?.textColor = errorColor @@ -129,9 +129,9 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { iconLabel?.textColor = editingOrSelected ? selectedIconColor : iconColor } } - + // MARK: Custom layout overrides - + /** Calculate the bounds for the textfield component of the control. Override to create a custom size textbox in the control. - parameter bounds: The current bounds of the textfield component @@ -179,19 +179,19 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { rect.size.width -= CGFloat(iconWidth + iconMarginLeft) return rect } - + /// Invoked by layoutIfNeeded automatically override open func layoutSubviews() { super.layoutSubviews() updateFrame() } - + fileprivate func updateFrame() { let textWidth: CGFloat = bounds.size.width if isLTRLanguage { iconLabel.frame = CGRect(x: 0, y: bounds.size.height - textHeight - iconMarginBottom, width: iconWidth, height: textHeight) } else { - iconLabel.frame = CGRect(x: textWidth - iconWidth , y: bounds.size.height - textHeight - iconMarginBottom, width: iconWidth, height: textHeight) + iconLabel.frame = CGRect(x: textWidth - iconWidth, y: bounds.size.height - textHeight - iconMarginBottom, width: iconWidth, height: textHeight) } } } From 6dc58ec24c1bda0bf1546dd4782fe895eb750298 Mon Sep 17 00:00:00 2001 From: Kevin Seidel Date: Thu, 13 Apr 2017 10:07:15 +0200 Subject: [PATCH 4/6] Revert ae49746c5eb7e038863ba18113debfc7e38b8588 --- .../Example4/IconTextField.swift | 8 +-- .../SkyFloatingLabelTextFieldTests.swift | 14 ++--- ...yFloatingLabelTextFieldWithIconTests.swift | 2 +- Sources/SkyFloatingLabelTextField.swift | 54 ++++++++++++------- .../SkyFloatingLabelTextFieldWithIcon.swift | 10 +++- 5 files changed, 55 insertions(+), 33 deletions(-) diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift index 3f9681a..3d88409 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Example4/IconTextField.swift @@ -97,14 +97,14 @@ public class IconTextField: SkyFloatingLabelTextField { if isLTRLanguage { iconLabel.frame = CGRect(x: 0, - y: bounds.size.height - textHeight, + y: bounds.size.height - textHeight(), width: iconWidth, - height: textHeight) + height: textHeight()) } else { iconLabel.frame = CGRect(x: textWidth - iconWidth, - y: bounds.size.height - textHeight, + y: bounds.size.height - textHeight(), width: iconWidth, - height: textHeight) + height: textHeight()) } } } diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift index 7f98fd4..65ef4ac 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldTests.swift @@ -589,7 +589,7 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { // swiftlint:disable:this typ let rect = floatingLabelTextField.editingRect(forBounds: bounds) // then - XCTAssertEqual(rect.height, boundsHeight - 4 - floatingLabelTextField.titleHeight) + XCTAssertEqual(rect.height, boundsHeight - 4 - floatingLabelTextField.titleHeight()) } // MARK: - control lifecycle events @@ -626,7 +626,7 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { // swiftlint:disable:this typ floatingLabelTextField.titleLabel = nil // then - XCTAssertEqual(floatingLabelTextField.titleHeight, 15) + XCTAssertEqual(floatingLabelTextField.titleHeight(), 15) } func test_whenTitleLabelHasFontSet_thenTitleHeightReturnsFontHeight() { @@ -635,7 +635,7 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { // swiftlint:disable:this typ floatingLabelTextField.titleLabel.font = font // then - XCTAssertEqual(floatingLabelTextField.titleHeight, font!.lineHeight) + XCTAssertEqual(floatingLabelTextField.titleHeight(), font!.lineHeight) } func test_whenTitleLabelHasFontSetToNil_thenFontSetToDefault() { @@ -654,7 +654,7 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { // swiftlint:disable:this typ floatingLabelTextField.font = font // then - XCTAssertEqual(floatingLabelTextField.textHeight, font!.lineHeight + 7) + XCTAssertEqual(floatingLabelTextField.textHeight(), font!.lineHeight + 7) } func test_whenTextFieldHasFontSetToNil_thenFontSetToDefault() { @@ -682,14 +682,14 @@ class SkyFloatingLabelTextFieldTests: XCTestCase { // swiftlint:disable:this typ func test_whenIntristicContentSizeInvoked_thenHeightIsTitleHeightAndContentHeightSize() { // given - XCTAssertNotEqual(floatingLabelTextField.titleHeight, 0) - XCTAssertNotEqual(floatingLabelTextField.textHeight, 0) + XCTAssertNotEqual(floatingLabelTextField.titleHeight(), 0) + XCTAssertNotEqual(floatingLabelTextField.textHeight(), 0) // when let size = floatingLabelTextField.intrinsicContentSize // then - XCTAssertEqual(size.height, floatingLabelTextField.titleHeight + floatingLabelTextField.textHeight) + XCTAssertEqual(size.height, floatingLabelTextField.titleHeight() + floatingLabelTextField.textHeight()) } // MARK: - Helpers diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift index b24e90f..0b14bb6 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldTests/SkyFloatingLabelTextFieldWithIconTests.swift @@ -73,7 +73,7 @@ class SkyFloatingLabelTextFieldWithIconTests: XCTestCase { // then let height = floatingLabelTextFieldWithIcon.bounds.size.height - let expectedHeight = height - floatingLabelTextFieldWithIcon.textHeight - 5 + let expectedHeight = height - floatingLabelTextFieldWithIcon.textHeight() - 5 XCTAssertEqual(floatingLabelTextFieldWithIcon.iconLabel.frame.origin.y, expectedHeight) } diff --git a/Sources/SkyFloatingLabelTextField.swift b/Sources/SkyFloatingLabelTextField.swift index 6187777..70e52f0 100644 --- a/Sources/SkyFloatingLabelTextField.swift +++ b/Sources/SkyFloatingLabelTextField.swift @@ -137,19 +137,6 @@ open class SkyFloatingLabelTextField: UITextField { // MARK: Properties - /// The computed height of the title label. Override to size the title with a different height - open var titleHeight: CGFloat { - guard let titleLabel = titleLabel, let font = titleLabel.font else { - return 15.0 - } - return font.lineHeight - } - - // The computed height of the text field. Override to size the textfield with a different height - open var textHeight: CGFloat { - return font!.lineHeight + 7.0 - } - /** The formatter to use before displaying content in the title label. This can be the `title`, `selectedTitle` or the `errorMessage`. The default implementation converts the text to uppercase. @@ -473,7 +460,10 @@ open class SkyFloatingLabelTextField: UITextField { */ override open func textRect(forBounds bounds: CGRect) -> CGRect { super.textRect(forBounds: bounds) - let rect = CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: bounds.size.height - titleHeight - selectedLineHeight) + let rect = CGRect(x: 0, + y: titleHeight(), + width: bounds.size.width, + height: bounds.size.height - titleHeight() - selectedLineHeight) return rect } @@ -483,7 +473,10 @@ open class SkyFloatingLabelTextField: UITextField { - returns: The rectangle that the textfield should render in */ override open func editingRect(forBounds bounds: CGRect) -> CGRect { - let rect = CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: bounds.size.height - titleHeight - selectedLineHeight) + let rect = CGRect(x: 0, + y: titleHeight(), + width: bounds.size.width, + height: bounds.size.height - titleHeight() - selectedLineHeight) return rect } @@ -493,7 +486,10 @@ open class SkyFloatingLabelTextField: UITextField { - returns: The rectangle that the placeholder should render in */ override open func placeholderRect(forBounds bounds: CGRect) -> CGRect { - let rect = CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: bounds.size.height - titleHeight - selectedLineHeight) + let rect = CGRect(x: 0, + y: titleHeight(), + width: bounds.size.width, + height: bounds.size.height - titleHeight() - selectedLineHeight) return rect } @@ -507,9 +503,9 @@ open class SkyFloatingLabelTextField: UITextField { */ open func titleLabelRectForBounds(_ bounds: CGRect, editing: Bool) -> CGRect { if editing { - return CGRect(x: 0, y: 0, width: bounds.size.width, height: titleHeight) + return CGRect(x: 0, y: 0, width: bounds.size.width, height: titleHeight()) } - return CGRect(x: 0, y: titleHeight, width: bounds.size.width, height: titleHeight) + return CGRect(x: 0, y: titleHeight(), width: bounds.size.width, height: titleHeight()) } /** @@ -523,6 +519,26 @@ open class SkyFloatingLabelTextField: UITextField { return CGRect(x: 0, y: bounds.size.height - height, width: bounds.size.width, height: height) } + /** + Calculate the height of the title label. + -returns: the calculated height of the title label. Override to size the title with a different height + */ + open func titleHeight() -> CGFloat { + if let titleLabel = titleLabel, + let font = titleLabel.font { + return font.lineHeight + } + return 15.0 + } + + /** + Calcualte the height of the textfield. + -returns: the calculated height of the textfield. Override to size the textfield with a different height + */ + open func textHeight() -> CGFloat { + return self.font!.lineHeight + 7.0 + } + // MARK: - Layout /// Invoked when the interface builder renders the control @@ -553,7 +569,7 @@ open class SkyFloatingLabelTextField: UITextField { - returns: the content size to be used for auto layout */ override open var intrinsicContentSize: CGSize { - return CGSize(width: bounds.size.width, height: titleHeight + textHeight) + return CGSize(width: bounds.size.width, height: titleHeight() + textHeight()) } // MARK: - Helpers diff --git a/Sources/SkyFloatingLabelTextFieldWithIcon.swift b/Sources/SkyFloatingLabelTextFieldWithIcon.swift index 7d48808..33fe830 100644 --- a/Sources/SkyFloatingLabelTextFieldWithIcon.swift +++ b/Sources/SkyFloatingLabelTextFieldWithIcon.swift @@ -189,9 +189,15 @@ open class SkyFloatingLabelTextFieldWithIcon: SkyFloatingLabelTextField { fileprivate func updateFrame() { let textWidth: CGFloat = bounds.size.width if isLTRLanguage { - iconLabel.frame = CGRect(x: 0, y: bounds.size.height - textHeight - iconMarginBottom, width: iconWidth, height: textHeight) + iconLabel.frame = CGRect(x: 0, + y: bounds.size.height - textHeight() - iconMarginBottom, + width: iconWidth, + height: textHeight()) } else { - iconLabel.frame = CGRect(x: textWidth - iconWidth, y: bounds.size.height - textHeight - iconMarginBottom, width: iconWidth, height: textHeight) + iconLabel.frame = CGRect(x: textWidth - iconWidth, + y: bounds.size.height - textHeight() - iconMarginBottom, + width: iconWidth, + height: textHeight()) } } } From 27df120073c9c29e92d5c523a9f55ebb9015aa40 Mon Sep 17 00:00:00 2001 From: moogle19 Date: Fri, 14 Apr 2017 20:50:03 +0200 Subject: [PATCH 5/6] Fix swiftlint to work correctly with XCode --- .swiftlint.yml | 4 +- .../project.pbxproj | 2 +- .../Base.lproj/Main.storyboard | 70 +++++++++---------- Sources/SkyFloatingLabelTextField.swift | 61 +++++++++------- .../SkyFloatingLabelTextFieldWithIcon.swift | 33 ++++++--- Sources/UITextField+fixCaretPosition.swift | 7 +- 6 files changed, 102 insertions(+), 75 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 02984e2..65d90f9 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,7 +1,7 @@ disabled_rules: opt_in_rules: included: - - Sources - - SkyFloatingLabelTextField + - ../Sources + - . excluded: diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextField.xcodeproj/project.pbxproj b/SkyFloatingLabelTextField/SkyFloatingLabelTextField.xcodeproj/project.pbxproj index f5cd01b..1262ddf 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextField.xcodeproj/project.pbxproj +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextField.xcodeproj/project.pbxproj @@ -400,7 +400,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; + shellScript = "if which swiftlint >/dev/null; then\n swiftlint lint --config ../.swiftlint.yml\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; }; /* End PBXShellScriptBuildPhase section */ diff --git a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Base.lproj/Main.storyboard b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Base.lproj/Main.storyboard index 1e8a25b..dbf5b20 100644 --- a/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Base.lproj/Main.storyboard +++ b/SkyFloatingLabelTextField/SkyFloatingLabelTextFieldExample/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -23,7 +23,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -43,13 +43,13 @@ -