Merge pull request #11 from TouchInstinct/fix/setting-initial-date
Fix/setting initial date
This commit is contained in:
commit
aee22c2cef
|
|
@ -0,0 +1,5 @@
|
|||
# Changelog
|
||||
|
||||
## 0.2.0
|
||||
|
||||
- **Fix**: date setting after picker presented.
|
||||
|
|
@ -128,12 +128,12 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0720;
|
||||
LastUpgradeCheck = 0820;
|
||||
LastUpgradeCheck = 0910;
|
||||
ORGANIZATIONNAME = CocoaPods;
|
||||
TargetAttributes = {
|
||||
607FACE41AFB9204008FA782 = {
|
||||
CreatedOnToolsVersion = 6.3.1;
|
||||
LastSwiftMigration = 0820;
|
||||
LastSwiftMigration = 0910;
|
||||
TestTargetID = 607FACCF1AFB9204008FA782;
|
||||
};
|
||||
};
|
||||
|
|
@ -173,9 +173,12 @@
|
|||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${SRCROOT}/Pods/Target Support Files/Pods-UIAnimatedTextField_Tests/Pods-UIAnimatedTextField_Tests-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/UIAnimatedTextField/UIAnimatedTextField.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/UIAnimatedTextField.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
|
|
@ -203,13 +206,16 @@
|
|||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-UIAnimatedTextField_Tests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
|
@ -234,14 +240,20 @@
|
|||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
|
|
@ -281,14 +293,20 @@
|
|||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
|
|
@ -326,7 +344,8 @@
|
|||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
|
@ -339,7 +358,8 @@
|
|||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0820"
|
||||
LastUpgradeVersion = "0910"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
|
|
@ -69,6 +70,7 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'UIAnimatedTextField'
|
||||
s.version = '0.1.13'
|
||||
s.version = '0.2.0'
|
||||
s.summary = 'UITextField with animated placeholder'
|
||||
s.description = <<-DESC
|
||||
This custom control can be used as a replacement for UITextField. It comes with 5 different text types: simple, password, url, tappable, date.
|
||||
|
|
|
|||
|
|
@ -24,10 +24,33 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
public class EditableTextField: UITextField {
|
||||
|
||||
var getType: (() -> TextType?)?
|
||||
|
||||
public enum EditableActionType {
|
||||
case selectAll
|
||||
case select
|
||||
case cut
|
||||
case copy
|
||||
case paste
|
||||
|
||||
public static let allActions: [EditableActionType] = [.selectAll, .select, .cut, .paste, .copy]
|
||||
}
|
||||
|
||||
open class EditableTextField: UITextField {
|
||||
|
||||
/// Actions, that will be disabled for this textField.
|
||||
/// By default no actions are disabled.
|
||||
open var disabledActions: [EditableActionType] = []
|
||||
|
||||
/// Allows to disable moving cursor for user
|
||||
open var pinCursorToEnd: Bool = false
|
||||
|
||||
open var getType: (() -> TextType?)?
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private var disabledSelectors: [Selector] {
|
||||
return disabledActions.map { selector(from: $0) }
|
||||
}
|
||||
|
||||
private let menuSelectors = [
|
||||
#selector(selectAll(_:)),
|
||||
#selector(select(_:)),
|
||||
|
|
@ -35,8 +58,14 @@ public class EditableTextField: UITextField {
|
|||
#selector(copy(_:)),
|
||||
#selector(paste(_:))
|
||||
]
|
||||
|
||||
// MARK: - Overriden
|
||||
|
||||
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
|
||||
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
|
||||
if disabledSelectors.contains(action) {
|
||||
return false
|
||||
}
|
||||
|
||||
guard let type = getType?() else {
|
||||
return super.canPerformAction(action, withSender: sender)
|
||||
}
|
||||
|
|
@ -50,7 +79,7 @@ public class EditableTextField: UITextField {
|
|||
return super.canPerformAction(action, withSender: sender)
|
||||
}
|
||||
|
||||
override public func caretRect(for position: UITextPosition) -> CGRect {
|
||||
override open func caretRect(for position: UITextPosition) -> CGRect {
|
||||
guard let type = getType?() else {
|
||||
return super.caretRect(for: position)
|
||||
}
|
||||
|
|
@ -61,5 +90,33 @@ public class EditableTextField: UITextField {
|
|||
|
||||
return super.caretRect(for: position)
|
||||
}
|
||||
|
||||
override open func closestPosition(to point: CGPoint) -> UITextPosition? {
|
||||
if pinCursorToEnd {
|
||||
return endOfDocument
|
||||
}
|
||||
|
||||
return super.closestPosition(to: point)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Private extensions
|
||||
|
||||
private extension UITextField {
|
||||
|
||||
func selector(from actionTyoe: EditableActionType) -> Selector {
|
||||
switch actionTyoe {
|
||||
case .selectAll:
|
||||
return #selector(selectAll(_:))
|
||||
case .select:
|
||||
return #selector(select(_:))
|
||||
case .cut:
|
||||
return #selector(cut(_:))
|
||||
case .copy:
|
||||
return #selector(copy(_:))
|
||||
case .paste:
|
||||
return #selector(paste(_:))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
||||
@objc 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 {
|
||||
|
||||
if textField.text?.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,
|
||||
|
|
@ -342,8 +349,13 @@ open class UIAnimatedTextField: UIView {
|
|||
return
|
||||
}
|
||||
|
||||
strongSelf.placeholderLabel.transform = strongSelf.placeholderLabelTransform(state: state)
|
||||
strongSelf.placeholderLabel.frame = strongSelf.placeholderLabelFrame(state: state)
|
||||
if strongSelf.isLeftTextAlignment {
|
||||
strongSelf.placeholderLabel.transform = strongSelf.placeholderLabelTransform(state: state)
|
||||
strongSelf.placeholderLabel.frame = strongSelf.placeholderLabelFrame(state: state)
|
||||
} else {
|
||||
strongSelf.placeholderLabel.frame = strongSelf.placeholderLabelFrame(state: state)
|
||||
strongSelf.placeholderLabel.transform = strongSelf.placeholderLabelTransform(state: state)
|
||||
}
|
||||
|
||||
switch state {
|
||||
case .placeholder:
|
||||
|
|
@ -354,50 +366,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,46 +420,46 @@ open class UIAnimatedTextField: UIView {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
|
||||
private func getDateInputView() -> UIDatePicker {
|
||||
let currentDate = Date()
|
||||
|
||||
|
||||
let datePicker = UIDatePicker()
|
||||
datePicker.timeZone = TimeZone(secondsFromGMT: 0)
|
||||
datePicker.datePickerMode = .date
|
||||
datePicker.backgroundColor = UIColor.white
|
||||
datePicker.setDate(currentDate, animated: true)
|
||||
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,
|
||||
target: self,
|
||||
action: #selector(datePickerDoneAction))
|
||||
let attributes = [
|
||||
NSForegroundColorAttributeName: UIColor.black
|
||||
NSAttributedStringKey.foregroundColor: doneTitleColor
|
||||
]
|
||||
|
||||
|
||||
doneItem.setTitleTextAttributes(attributes, for: .normal)
|
||||
|
||||
toolbar.items = [spacerItem, doneItem]
|
||||
|
||||
|
||||
toolbar.setItems([spacerItem, doneItem], animated: false)
|
||||
|
||||
return toolbar
|
||||
}
|
||||
|
||||
|
|
@ -455,60 +467,60 @@ 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 {
|
||||
if textField.text?.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 {
|
||||
if textField.text?.count ?? 0 == 0 {
|
||||
setState(toState: .placeholder, duration: UIAnimatedTextField.animationDuration)
|
||||
}
|
||||
|
||||
|
|
@ -518,21 +530,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 +552,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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue