From c5bf32e147cc5149b6203c36590ad28e6fb37c13 Mon Sep 17 00:00:00 2001 From: Igor Kislyuk Date: Mon, 30 Oct 2017 10:23:59 +0300 Subject: [PATCH] Update to background color --- .../Source/UIAnimatedTextField.swift | 213 +++++++++--------- 1 file changed, 110 insertions(+), 103 deletions(-) diff --git a/UIAnimatedTextField/Source/UIAnimatedTextField.swift b/UIAnimatedTextField/Source/UIAnimatedTextField.swift index ef1a775..0efdcbd 100644 --- a/UIAnimatedTextField/Source/UIAnimatedTextField.swift +++ b/UIAnimatedTextField/Source/UIAnimatedTextField.swift @@ -25,7 +25,7 @@ import UIKit @objc public protocol UIAnimatedTextFieldDelegate: class { - + @objc optional func animatedTextFieldValueDidChange(_ animatedTextField: UIAnimatedTextField) @objc optional func animatedTextFieldWillReactForTap() @objc optional func animatedTextFieldShouldBeginEditing(_ animatedTextField: UIAnimatedTextField) -> Bool @@ -37,7 +37,7 @@ import UIKit replacementString string: String) -> Bool @objc optional func animatedTextFieldShouldClear(_ animatedTextField: UIAnimatedTextField) -> Bool @objc optional func animatedTextFieldShouldReturn(_ animatedTextField: UIAnimatedTextField) -> Bool - + } public enum AnimatedTextFieldState { @@ -55,28 +55,28 @@ public enum TextType { @IBDesignable open class UIAnimatedTextField: UIView { - + // MARK: - Constants struct Constants { static let done = "Done" static let space = " " static let defaultDateFormat = "dd/MM/yyyy" } - + // MARK: - Delegate - + weak public var delegate: UIAnimatedTextFieldDelegate? - + // MARK: - UI Properties - + private(set) public var textField: EditableTextField! private(set) public var placeholderLabel: UILabel! private(set) public var lineView: UIView! - + private var disclosureIndicatorImageView: UIImageView! - + // MARK: - @IBInspectable Properties - + @IBInspectable public var placeholder: String? { get { return placeholderLabel.text @@ -85,7 +85,7 @@ open class UIAnimatedTextField: UIView { placeholderLabel.text = newValue } } - + @IBInspectable public var isLeftTextAlignment: Bool { get { return textField.textAlignment == .left @@ -96,7 +96,7 @@ open class UIAnimatedTextField: UIView { placeholderLabel.textAlignment = alignment } } - + @IBInspectable public var placeholderTopColor: UIColor = UIColor.gray { didSet { setState(toState: state) @@ -107,19 +107,19 @@ open class UIAnimatedTextField: UIView { setState(toState: state) } } - + @IBInspectable public var enteredTextColor: UIColor { get { return textField.textColor ?? UIColor.black } set { textField.textColor = newValue } } - + @IBInspectable public var lineColor: UIColor { get { return lineView.backgroundColor ?? UIColor.gray } set { lineView.backgroundColor = newValue } } - + // MARK: - Public Properties - + public var text: String? { get { return textField.text @@ -140,7 +140,7 @@ open class UIAnimatedTextField: UIView { placeholderLabel.font = newValue } } - + public var isDisclosureIndicatorVisible: Bool = false { didSet { disclosureIndicatorImageView.isHidden = !isDisclosureIndicatorVisible @@ -156,15 +156,15 @@ open class UIAnimatedTextField: UIView { textField.autocapitalizationType = .words textField.inputView = nil textField.inputAccessoryView = nil - + tapAction = nil isDisclosureIndicatorVisible = false - + if let tapGestureRecognizer = tapGestureRecognizer { removeGestureRecognizer(tapGestureRecognizer) self.tapGestureRecognizer = nil } - + switch type { case .password: textField.isSecureTextEntry = true @@ -178,7 +178,7 @@ open class UIAnimatedTextField: UIView { tapAction = action textField.isUserInteractionEnabled = false isDisclosureIndicatorVisible = true - + tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapGestureRecognizerAction(_:))) if let tapGestureRecognizer = tapGestureRecognizer { addGestureRecognizer(tapGestureRecognizer) @@ -193,48 +193,55 @@ open class UIAnimatedTextField: UIView { } } } - + public dynamic var selectedDate: Date? public var dateFormat: String = Constants.defaultDateFormat + public var doneTitle: String = Constants.done { didSet { textField.inputAccessoryView = getDateInputAccessoryView() } } - + + public var doneTitleColor: UIColor = .black { + didSet { + textField.inputAccessoryView = getDateInputAccessoryView() + } + } + // MARK: - Static Properties - + static public let animationDuration: TimeInterval = 0.3 static public let disclosureIndicatorWidth = 15.0 - + // MARK: - Private Properties - + private var tapGestureRecognizer: UITapGestureRecognizer? private var tapAction: ((_ animatedTextField: UIAnimatedTextField) -> Void)? private var isShownInfo: Bool = false - + private var state: AnimatedTextFieldState { var state: AnimatedTextFieldState = .placeholder - + if textField.text?.characters.count ?? 0 > 0 || textField.isFirstResponder { state = .text } - + return state } - + // MARK: - Initialization - + override public init(frame: CGRect) { super.init(frame: frame) initialization() } - + required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) initialization() } - + private func initialization() { textField = EditableTextField() textField.delegate = self @@ -244,7 +251,7 @@ open class UIAnimatedTextField: UIView { return self?.type } addSubview(textField) - + placeholderLabel = UILabel() placeholderLabel.isUserInteractionEnabled = false placeholderLabel.textColor = placeholderBottomColor @@ -252,50 +259,50 @@ open class UIAnimatedTextField: UIView { placeholderLabel.adjustsFontSizeToFitWidth = true placeholderLabel.minimumScaleFactor = 0.5 addSubview(placeholderLabel) - + lineView = UIView() lineView.backgroundColor = placeholderLabel.textColor addSubview(lineView) - + disclosureIndicatorImageView = UIImageView() disclosureIndicatorImageView.image = UIImage(named: "disclosureIndicator") disclosureIndicatorImageView.contentMode = .center disclosureIndicatorImageView.isHidden = true addSubview(disclosureIndicatorImageView) - + layoutSubviews() } - + // MARK: - Layout - + private func textFieldFrame() -> CGRect { var size = bounds.size var origin = bounds.origin - + size.height = 2/3 * size.height origin.y = 1/3 * bounds.size.height - + if isDisclosureIndicatorVisible { origin.x += CGFloat(UIAnimatedTextField.disclosureIndicatorWidth) size.width -= CGFloat(UIAnimatedTextField.disclosureIndicatorWidth) * 2 } - + let textFieldBounds = CGRect(origin: origin, size: size) return textFieldBounds } - + private func placeholderLabelFrame(state: AnimatedTextFieldState) -> CGRect { if state == .placeholder { return textFieldFrame() } else { var size = bounds.size size.height = 1/3 * size.height - + let placeholderLabelBounds = CGRect(origin: bounds.origin, size: size) return placeholderLabelBounds } } - + private func disclosureIndicatorFrame() -> CGRect { let fieldFrame = textFieldFrame() let frame = CGRect(x: bounds.width - CGFloat(UIAnimatedTextField.disclosureIndicatorWidth), @@ -304,7 +311,7 @@ open class UIAnimatedTextField: UIView { height: fieldFrame.height) return frame } - + private func placeholderLabelTransform(state: AnimatedTextFieldState) -> CGAffineTransform { if state == .placeholder { return CGAffineTransform.identity @@ -312,26 +319,26 @@ open class UIAnimatedTextField: UIView { return CGAffineTransform(scaleX: 0.8, y: 0.8) } } - + override open func layoutSubviews() { super.layoutSubviews() - + textField.frame = textFieldFrame() - + if isDisclosureIndicatorVisible { disclosureIndicatorImageView.frame = disclosureIndicatorFrame() } - + setState(toState: state, duration: 0) - + lineView.frame = CGRect(x: 0, y: bounds.height - UIView.onePixelInPoints * 2, width: bounds.width, height: UIView.onePixelInPoints) } - + // MARK: - Animation - + public func setState(toState state: AnimatedTextFieldState, duration: TimeInterval = 0) { UIView.animate( withDuration: duration, @@ -354,50 +361,50 @@ open class UIAnimatedTextField: UIView { }, completion: nil) } - + // MARK: - Actions - + @objc private func tapGestureRecognizerAction(_ sender: UITapGestureRecognizer) { delegate?.animatedTextFieldWillReactForTap?() tapAction?(self) } - + open func validateText() -> Bool { guard let text = textField.text else { return false } - + switch type { case .url: return text.isValidEmail default: break } - + return true } - + open func showInfo(infoText: String) { guard !isShownInfo else { return } - + isShownInfo = true - + let currentPlaceholder = placeholder - + UIView.transition(with: placeholderLabel, duration: 0.5, options: .transitionFlipFromTop, animations: { [weak self] in self?.placeholder = infoText }, completion: nil) - + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { [weak self] in guard let placeholderLabel = self?.placeholderLabel else { return } - + UIView.transition(with: placeholderLabel, duration: 0.5, options: .transitionFlipFromBottom, @@ -408,12 +415,12 @@ open class UIAnimatedTextField: UIView { }) } } - + // MARK: - Private - + private func getDateInputView() -> UIDatePicker { let currentDate = Date() - + let datePicker = UIDatePicker() datePicker.timeZone = TimeZone(secondsFromGMT: 0) datePicker.datePickerMode = .date @@ -421,33 +428,33 @@ open class UIAnimatedTextField: UIView { datePicker.setDate(selectedDate ?? currentDate, animated: true) datePicker.maximumDate = currentDate datePicker.addTarget(self, action: #selector(datePickerValueChanged(_:)), for: .valueChanged) - + return datePicker } - + @objc private func datePickerValueChanged(_ datePicker: UIDatePicker) { updateText(from: datePicker) } - + private func getDateInputAccessoryView() -> UIView { let toolbar = UIToolbar() toolbar.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 44) toolbar.autoresizingMask = [.flexibleWidth] toolbar.barTintColor = UIColor.white - + let spacerItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let doneItem = UIBarButtonItem(title: doneTitle, - style: .done, + style: .plain, target: self, action: #selector(datePickerDoneAction)) let attributes = [ - NSForegroundColorAttributeName: UIColor.black + NSForegroundColorAttributeName: doneTitleColor ] - + doneItem.setTitleTextAttributes(attributes, for: .normal) - - toolbar.items = [spacerItem, doneItem] - + + toolbar.setItems([spacerItem, doneItem], animated: false) + return toolbar } @@ -455,58 +462,58 @@ open class UIAnimatedTextField: UIView { selectedDate = datePicker.date text = datePicker.date.toString(withFormat: dateFormat) } - + @objc private func datePickerDoneAction() { if let datePicker = textField.inputView as? UIDatePicker { updateText(from: datePicker) } textField.resignFirstResponder() } - + @objc private func textFieldValueDidChange() { delegate?.animatedTextFieldValueDidChange?(self) } - + } // MARK: - Extension extension UIAnimatedTextField: UITextFieldDelegate { - + open func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { var result = true - + if let delegateResult = delegate?.animatedTextFieldShouldBeginEditing?(self) { result = delegateResult } - + return result } - + open func textFieldDidBeginEditing(_ textField: UITextField) { if textField.text?.characters.count ?? 0 == 0 { setState(toState: .text, duration: UIAnimatedTextField.animationDuration) } - + if case .date = type { if let datePicker = textField.inputView as? UIDatePicker { textField.text = datePicker.date.toString(withFormat: dateFormat) } } - + delegate?.animatedTextFieldDidBeginEditing?(self) } - + open func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { var result = true - + if let delegateResult = delegate?.animatedTextFieldShouldEndEditing?(self) { result = delegateResult } - + return result } - + open func textFieldDidEndEditing(_ textField: UITextField) { if textField.text?.characters.count ?? 0 == 0 { setState(toState: .placeholder, duration: UIAnimatedTextField.animationDuration) @@ -518,21 +525,21 @@ extension UIAnimatedTextField: UITextFieldDelegate { delegate?.animatedTextFieldDidEndEditing?(self) } - + open func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, - replacementString string: String) -> Bool { + replacementString string: String) -> Bool { var result = true - + if let delegateResult = delegate?.animatedTextField?(self, shouldChangeCharactersInRange: range, replacementString: string) { result = delegateResult } - + if string == Constants.space { if textField.text?.isEmpty ?? true { result = false } - + switch type { case .password, .url: result = false @@ -540,28 +547,28 @@ extension UIAnimatedTextField: UITextFieldDelegate { break } } - + return result } - + open func textFieldShouldClear(_ textField: UITextField) -> Bool { var result = true - + if let delegateResult = delegate?.animatedTextFieldShouldClear?(self) { result = delegateResult } - + return result } - + open func textFieldShouldReturn(_ textField: UITextField) -> Bool { var result = true - + if let delegateResult = delegate?.animatedTextFieldShouldReturn?(self) { result = delegateResult } - + return result } - + }