Compare commits

...

33 Commits

Author SHA1 Message Date
Alexey Gerasimov 51067b408f
Merge pull request #13 from TouchInstinct/feature/swift4.2
Fixed for Swift4.2
2018-10-16 11:17:37 +03:00
Alexey Gerasimov b78e31424b Fixed for Swift4.2 2018-10-16 11:07:28 +03:00
Igor Kislyuk ee5ef07506
Merge pull request #12 from TouchInstinct/fix/swift-version
Add swift version
2017-12-04 11:53:00 +03:00
Igor Kislyuk 2c186fb3de Add swift version 2017-12-04 11:50:30 +03:00
Igor Kislyuk aee22c2cef
Merge pull request #11 from TouchInstinct/fix/setting-initial-date
Fix/setting initial date
2017-12-04 11:43:50 +03:00
Igor Kislyuk cf9b3a72c5 PR fix 2017-12-04 11:42:52 +03:00
Igor Kislyuk 9bb955a4fe Fix bug with animation 2017-11-20 17:48:55 +03:00
Igor Kislyuk 9dea74461e Update for swift 4 2017-11-18 19:54:14 +03:00
Igor Kislyuk 17ddd2c3b7 Fix access level 2017-11-12 01:30:41 +03:00
Igor Kislyuk 7041eb4107 Update
- fix swift 4 warnings
- add posibility to disable actions
- add functionality to disable moving cursor
2017-11-12 01:25:06 +03:00
Igor Kislyuk 7a0d673396 Fix done title 2017-10-30 10:27:46 +03:00
Igor Kislyuk c5bf32e147 Update to background color 2017-10-30 10:23:59 +03:00
Igor Kislyuk 4adfe1489c Update for setting date 2017-10-18 02:43:44 +03:00
Nikolai Ashanin 297ef68850 Merge pull request #9 from TouchInstinct/fix/focus-bug
Fix. Bug with no-value after textfield lose it focus
2017-05-18 23:04:19 +03:00
Igor Kislyuk cba697954b Fix. Update pod spec 2017-05-18 22:35:17 +03:00
Igor Kislyuk de0e9adcab Fix. Bug with no-value after textfield lose it focus 2017-05-18 22:34:29 +03:00
Nikolai Ashanin 352af583cc Merge pull request #8 from TouchInstinct/bugfix/kvo
Fix. KVO & value passing
2017-04-27 13:51:35 +03:00
Igor Kislyuk 1425bbe004 Fix. KVO & value passing 2017-04-27 13:43:37 +03:00
Grigory 11c69147ed Merge pull request #7 from TouchInstinct/leftAlignmentFix
Left alignment fix
2017-04-11 16:36:33 +03:00
Grigory 1d9541158e new version 2017-04-11 16:34:38 +03:00
Grigory c2a78d6b7b animation fixed 2017-04-11 16:32:52 +03:00
Grigory 720d0f404c Merge pull request #6 from TouchInstinct/bugfix/colorChangeUIUpdate
new pod version
2017-01-26 16:02:51 +03:00
Grigory Ulanov c635cd1688 new pod version 2017-01-26 16:02:17 +03:00
Grigory 40ad393cbe Merge pull request #5 from TouchInstinct/bugfix/colorChangeUIUpdate
colors fixed
2017-01-26 16:01:24 +03:00
Grigory Ulanov 7883afcd74 colors fixed 2017-01-26 15:59:30 +03:00
Grigory 6924be8cee Merge pull request #4 from TouchInstinct/feature/open
open functions
2017-01-17 17:50:57 +03:00
Grigory Ulanov ad91c59c5b open functions 2017-01-17 17:32:34 +03:00
Grigory 8278bf17e3 Merge pull request #3 from TouchInstinct/bugfix/dateFormatter
dateformatter fixed
2017-01-12 17:53:26 +03:00
Grigory Ulanov e0c5ca347e dateformatter fixed 2017-01-12 17:52:24 +03:00
Nikolai Ashanin f5d6144142 Merge pull request #2 from TouchInstinct/fix/editPodspec
Edit pod spec
2016-12-23 14:38:28 +03:00
Ivan Zinovyev 81141f5784 Edit pod spec 2016-12-23 14:37:41 +03:00
Ivan Zinovyev 651a930ac3 Edit read 2016-12-20 19:35:55 +03:00
Ivan Zinovyev 808c549913 Edit read 2016-12-20 19:31:36 +03:00
12 changed files with 299 additions and 162 deletions

1
.swift-version Normal file
View File

@ -0,0 +1 @@
4.0

5
CHANGELOG.md Normal file
View File

@ -0,0 +1,5 @@
# Changelog
## 0.2.0
- **Fix**: date setting after picker presented.

View File

@ -12,7 +12,7 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
12D59B30305289F1A0BAB148 /* UIAnimatedTextField.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = UIAnimatedTextField.podspec; path = ../UIAnimatedTextField.podspec; sourceTree = "<group>"; }; 12D59B30305289F1A0BAB148 /* UIAnimatedTextField.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = UIAnimatedTextField.podspec; path = ../UIAnimatedTextField.podspec; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
3023902FA98A29EAE27CE743 /* Pods_UIAnimatedTextField_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_UIAnimatedTextField_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3023902FA98A29EAE27CE743 /* Pods_UIAnimatedTextField_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_UIAnimatedTextField_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
305D07AC233331112B594740 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; }; 305D07AC233331112B594740 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
3EE19024E4B841DD8F1FEA61 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; }; 3EE19024E4B841DD8F1FEA61 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
@ -110,7 +110,6 @@
607FACE21AFB9204008FA782 /* Frameworks */, 607FACE21AFB9204008FA782 /* Frameworks */,
607FACE31AFB9204008FA782 /* Resources */, 607FACE31AFB9204008FA782 /* Resources */,
4EB68626CEDBCD2943AF13ED /* [CP] Embed Pods Frameworks */, 4EB68626CEDBCD2943AF13ED /* [CP] Embed Pods Frameworks */,
AFE96432D6D5B8E3FF680C55 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@ -128,12 +127,12 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0720; LastSwiftUpdateCheck = 0720;
LastUpgradeCheck = 0820; LastUpgradeCheck = 1000;
ORGANIZATIONNAME = CocoaPods; ORGANIZATIONNAME = CocoaPods;
TargetAttributes = { TargetAttributes = {
607FACE41AFB9204008FA782 = { 607FACE41AFB9204008FA782 = {
CreatedOnToolsVersion = 6.3.1; CreatedOnToolsVersion = 6.3.1;
LastSwiftMigration = 0820; LastSwiftMigration = 0910;
TestTargetID = 607FACCF1AFB9204008FA782; TestTargetID = 607FACCF1AFB9204008FA782;
}; };
}; };
@ -173,43 +172,34 @@
files = ( files = (
); );
inputPaths = ( 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"; name = "[CP] Embed Pods Frameworks";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/UIAnimatedTextField.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-UIAnimatedTextField_Tests/Pods-UIAnimatedTextField_Tests-frameworks.sh\"\n"; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-UIAnimatedTextField_Tests/Pods-UIAnimatedTextField_Tests-frameworks.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
AFE96432D6D5B8E3FF680C55 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-UIAnimatedTextField_Tests/Pods-UIAnimatedTextField_Tests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
D458C72BE72F89E2185E2C11 /* [CP] Check Pods Manifest.lock */ = { D458C72BE72F89E2185E2C11 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
); );
name = "[CP] Check Pods Manifest.lock"; name = "[CP] Check Pods Manifest.lock";
outputPaths = ( outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-UIAnimatedTextField_Tests-checkManifestLockResult.txt",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; 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; showEnvVarsInLog = 0;
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
@ -234,14 +224,22 @@
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 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_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@ -281,14 +279,22 @@
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 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_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@ -326,7 +332,8 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.2;
}; };
name = Debug; name = Debug;
}; };
@ -339,7 +346,8 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.2;
}; };
name = Release; name = Release;
}; };

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0820" LastUpgradeVersion = "1000"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -16,7 +16,7 @@ platform :ios, '9.0'
use_frameworks! use_frameworks!
target "ProjectName" do target "ProjectName" do
pod 'UIAnimatedTextField' pod 'UIAnimatedTextField', '0.1.7'
end end
``` ```
@ -67,6 +67,32 @@ textField.type = .tappable(action: {textField in textField.text = "Selected thin
``` ```
Tap on the field, do an action, display a result in text field. Tap on the field, do an action, display a result in text field.
## Customization
### Color
You can change color of placeholder, entered text, line like this:
```swift
textField.placeholderTopColor = .blue
textField.placeholderBottomColor = .brown
textField.enteredTextColor = .orange
textField.lineColor = .green
```
Result:
<img src="https://raw.githubusercontent.com/iznv/UIAnimatedTextField/master/UIAnimatedTextField/Screenshots/custom1.png" width="300">
<img src="https://raw.githubusercontent.com/iznv/UIAnimatedTextField/master/UIAnimatedTextField/Screenshots/custom2.png" width="300">
### Text Alignment
In order to change text alignment of placeholder and text field use this property:
```swift
textField.isLeftTextAlignment = true
```
Result:
<img src="https://raw.githubusercontent.com/iznv/UIAnimatedTextField/master/UIAnimatedTextField/Screenshots/custom3.png" width="300">
## License ## License
Copyright (c) 2016 Touch Instinct Copyright (c) 2016 Touch Instinct

View File

@ -1,14 +1,14 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'UIAnimatedTextField' s.name = 'UIAnimatedTextField'
s.version = '0.1.7' s.version = '0.3.0'
s.summary = 'UITextField with animated placeholder' s.summary = 'UITextField with animated placeholder'
s.description = <<-DESC 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. This custom control can be used as a replacement for UITextField. It comes with 5 different text types: simple, password, url, tappable, date.
DESC DESC
s.homepage = 'https://github.com/iznv/UIAnimatedTextField' s.homepage = 'https://github.com/TouchInstinct/UIAnimatedTextField'
s.license = { :type => 'MIT', :file => 'LICENSE' } s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'Ivan Zinovyev' => 'ivan.zinovyev@touchin.ru' } s.author = "Touch Instinct"
s.source = { :git => 'https://github.com/iznv/UIAnimatedTextField.git', :tag => s.version.to_s } s.source = { :git => 'https://github.com/TouchInstinct/UIAnimatedTextField.git', :tag => s.version.to_s }
s.ios.deployment_target = '8.0' s.ios.deployment_target = '8.0'
s.source_files = 'UIAnimatedTextField/Source/**/*' s.source_files = 'UIAnimatedTextField/Source/**/*'
s.frameworks = 'UIKit' s.frameworks = 'UIKit'

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@ -24,10 +24,33 @@
import Foundation import Foundation
public class EditableTextField: UITextField { public enum EditableActionType {
case selectAll
var getType: (() -> TextType?)? 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 = [ private let menuSelectors = [
#selector(selectAll(_:)), #selector(selectAll(_:)),
#selector(select(_:)), #selector(select(_:)),
@ -35,8 +58,14 @@ public class EditableTextField: UITextField {
#selector(copy(_:)), #selector(copy(_:)),
#selector(paste(_:)) #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 { guard let type = getType?() else {
return super.canPerformAction(action, withSender: sender) return super.canPerformAction(action, withSender: sender)
} }
@ -50,7 +79,7 @@ public class EditableTextField: UITextField {
return super.canPerformAction(action, withSender: sender) 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 { guard let type = getType?() else {
return super.caretRect(for: position) return super.caretRect(for: position)
} }
@ -61,5 +90,33 @@ public class EditableTextField: UITextField {
return super.caretRect(for: position) 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(_:))
}
}
}

View File

@ -25,7 +25,7 @@
import UIKit import UIKit
@objc public protocol UIAnimatedTextFieldDelegate: class { @objc public protocol UIAnimatedTextFieldDelegate: class {
@objc optional func animatedTextFieldValueDidChange(_ animatedTextField: UIAnimatedTextField) @objc optional func animatedTextFieldValueDidChange(_ animatedTextField: UIAnimatedTextField)
@objc optional func animatedTextFieldWillReactForTap() @objc optional func animatedTextFieldWillReactForTap()
@objc optional func animatedTextFieldShouldBeginEditing(_ animatedTextField: UIAnimatedTextField) -> Bool @objc optional func animatedTextFieldShouldBeginEditing(_ animatedTextField: UIAnimatedTextField) -> Bool
@ -37,7 +37,7 @@ import UIKit
replacementString string: String) -> Bool replacementString string: String) -> Bool
@objc optional func animatedTextFieldShouldClear(_ animatedTextField: UIAnimatedTextField) -> Bool @objc optional func animatedTextFieldShouldClear(_ animatedTextField: UIAnimatedTextField) -> Bool
@objc optional func animatedTextFieldShouldReturn(_ animatedTextField: UIAnimatedTextField) -> Bool @objc optional func animatedTextFieldShouldReturn(_ animatedTextField: UIAnimatedTextField) -> Bool
} }
public enum AnimatedTextFieldState { public enum AnimatedTextFieldState {
@ -54,29 +54,29 @@ public enum TextType {
} }
@IBDesignable @IBDesignable
public class UIAnimatedTextField: UIView { open class UIAnimatedTextField: UIView {
// MARK: - Constants // MARK: - Constants
struct Constants { struct Constants {
static let done = "Done" static let done = "Done"
static let space = " " static let space = " "
static let defaultDateFormat = "dd/MM/YYYY" static let defaultDateFormat = "dd/MM/yyyy"
} }
// MARK: - Delegate // MARK: - Delegate
weak public var delegate: UIAnimatedTextFieldDelegate? weak public var delegate: UIAnimatedTextFieldDelegate?
// MARK: - UI Properties // MARK: - UI Properties
private(set) public var textField: EditableTextField! private(set) public var textField: EditableTextField!
private(set) public var placeholderLabel: UILabel! private(set) public var placeholderLabel: UILabel!
private(set) public var lineView: UIView! private(set) public var lineView: UIView!
private var disclosureIndicatorImageView: UIImageView! private var disclosureIndicatorImageView: UIImageView!
// MARK: - @IBInspectable Properties // MARK: - @IBInspectable Properties
@IBInspectable public var placeholder: String? { @IBInspectable public var placeholder: String? {
get { get {
return placeholderLabel.text return placeholderLabel.text
@ -85,7 +85,7 @@ public class UIAnimatedTextField: UIView {
placeholderLabel.text = newValue placeholderLabel.text = newValue
} }
} }
@IBInspectable public var isLeftTextAlignment: Bool { @IBInspectable public var isLeftTextAlignment: Bool {
get { get {
return textField.textAlignment == .left return textField.textAlignment == .left
@ -96,22 +96,30 @@ public class UIAnimatedTextField: UIView {
placeholderLabel.textAlignment = alignment placeholderLabel.textAlignment = alignment
} }
} }
@IBInspectable public var placeholderTopColor: UIColor = UIColor.gray @IBInspectable public var placeholderTopColor: UIColor = UIColor.gray {
@IBInspectable public var placeholderBottomColor: UIColor = UIColor.gray didSet {
setState(toState: state)
}
}
@IBInspectable public var placeholderBottomColor: UIColor = UIColor.gray {
didSet {
setState(toState: state)
}
}
@IBInspectable public var enteredTextColor: UIColor { @IBInspectable public var enteredTextColor: UIColor {
get { return textField.textColor ?? UIColor.black } get { return textField.textColor ?? UIColor.black }
set { textField.textColor = newValue } set { textField.textColor = newValue }
} }
@IBInspectable public var lineColor: UIColor { @IBInspectable public var lineColor: UIColor {
get { return lineView.backgroundColor ?? UIColor.gray } get { return lineView.backgroundColor ?? UIColor.gray }
set { lineView.backgroundColor = newValue } set { lineView.backgroundColor = newValue }
} }
// MARK: - Public Properties // MARK: - Public Properties
public var text: String? { public var text: String? {
get { get {
return textField.text return textField.text
@ -132,7 +140,7 @@ public class UIAnimatedTextField: UIView {
placeholderLabel.font = newValue placeholderLabel.font = newValue
} }
} }
public var isDisclosureIndicatorVisible: Bool = false { public var isDisclosureIndicatorVisible: Bool = false {
didSet { didSet {
disclosureIndicatorImageView.isHidden = !isDisclosureIndicatorVisible disclosureIndicatorImageView.isHidden = !isDisclosureIndicatorVisible
@ -148,15 +156,15 @@ public class UIAnimatedTextField: UIView {
textField.autocapitalizationType = .words textField.autocapitalizationType = .words
textField.inputView = nil textField.inputView = nil
textField.inputAccessoryView = nil textField.inputAccessoryView = nil
tapAction = nil tapAction = nil
isDisclosureIndicatorVisible = false isDisclosureIndicatorVisible = false
if let tapGestureRecognizer = tapGestureRecognizer { if let tapGestureRecognizer = tapGestureRecognizer {
removeGestureRecognizer(tapGestureRecognizer) removeGestureRecognizer(tapGestureRecognizer)
self.tapGestureRecognizer = nil self.tapGestureRecognizer = nil
} }
switch type { switch type {
case .password: case .password:
textField.isSecureTextEntry = true textField.isSecureTextEntry = true
@ -170,7 +178,7 @@ public class UIAnimatedTextField: UIView {
tapAction = action tapAction = action
textField.isUserInteractionEnabled = false textField.isUserInteractionEnabled = false
isDisclosureIndicatorVisible = true isDisclosureIndicatorVisible = true
tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapGestureRecognizerAction(_:))) tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapGestureRecognizerAction(_:)))
if let tapGestureRecognizer = tapGestureRecognizer { if let tapGestureRecognizer = tapGestureRecognizer {
addGestureRecognizer(tapGestureRecognizer) addGestureRecognizer(tapGestureRecognizer)
@ -185,48 +193,55 @@ public class UIAnimatedTextField: UIView {
} }
} }
} }
public var selectedDate: Date? @objc public dynamic var selectedDate: Date?
public var dateFormat: String = Constants.defaultDateFormat public var dateFormat: String = Constants.defaultDateFormat
public var doneTitle: String = Constants.done { public var doneTitle: String = Constants.done {
didSet { didSet {
textField.inputAccessoryView = getDateInputAccessoryView() textField.inputAccessoryView = getDateInputAccessoryView()
} }
} }
public var doneTitleColor: UIColor = .black {
didSet {
textField.inputAccessoryView = getDateInputAccessoryView()
}
}
// MARK: - Static Properties // MARK: - Static Properties
static public let animationDuration: TimeInterval = 0.3 static public let animationDuration: TimeInterval = 0.3
static public let disclosureIndicatorWidth = 15.0 static public let disclosureIndicatorWidth = 15.0
// MARK: - Private Properties // MARK: - Private Properties
private var tapGestureRecognizer: UITapGestureRecognizer? private var tapGestureRecognizer: UITapGestureRecognizer?
private var tapAction: ((_ animatedTextField: UIAnimatedTextField) -> Void)? private var tapAction: ((_ animatedTextField: UIAnimatedTextField) -> Void)?
private var isShownInfo: Bool = false private var isShownInfo: Bool = false
private var state: AnimatedTextFieldState { private var state: AnimatedTextFieldState {
var state: AnimatedTextFieldState = .placeholder var state: AnimatedTextFieldState = .placeholder
if textField.text?.characters.count ?? 0 > 0 || textField.isFirstResponder { if textField.text?.count ?? 0 > 0 || textField.isFirstResponder {
state = .text state = .text
} }
return state return state
} }
// MARK: - Initialization // MARK: - Initialization
override public init(frame: CGRect) { override public init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
initialization() initialization()
} }
required public init?(coder aDecoder: NSCoder) { required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder) super.init(coder: aDecoder)
initialization() initialization()
} }
private func initialization() { private func initialization() {
textField = EditableTextField() textField = EditableTextField()
textField.delegate = self textField.delegate = self
@ -236,7 +251,7 @@ public class UIAnimatedTextField: UIView {
return self?.type return self?.type
} }
addSubview(textField) addSubview(textField)
placeholderLabel = UILabel() placeholderLabel = UILabel()
placeholderLabel.isUserInteractionEnabled = false placeholderLabel.isUserInteractionEnabled = false
placeholderLabel.textColor = placeholderBottomColor placeholderLabel.textColor = placeholderBottomColor
@ -244,50 +259,50 @@ public class UIAnimatedTextField: UIView {
placeholderLabel.adjustsFontSizeToFitWidth = true placeholderLabel.adjustsFontSizeToFitWidth = true
placeholderLabel.minimumScaleFactor = 0.5 placeholderLabel.minimumScaleFactor = 0.5
addSubview(placeholderLabel) addSubview(placeholderLabel)
lineView = UIView() lineView = UIView()
lineView.backgroundColor = placeholderLabel.textColor lineView.backgroundColor = placeholderLabel.textColor
addSubview(lineView) addSubview(lineView)
disclosureIndicatorImageView = UIImageView() disclosureIndicatorImageView = UIImageView()
disclosureIndicatorImageView.image = UIImage(named: "disclosureIndicator") disclosureIndicatorImageView.image = UIImage(named: "disclosureIndicator")
disclosureIndicatorImageView.contentMode = .center disclosureIndicatorImageView.contentMode = .center
disclosureIndicatorImageView.isHidden = true disclosureIndicatorImageView.isHidden = true
addSubview(disclosureIndicatorImageView) addSubview(disclosureIndicatorImageView)
layoutSubviews() layoutSubviews()
} }
// MARK: - Layout // MARK: - Layout
private func textFieldFrame() -> CGRect { private func textFieldFrame() -> CGRect {
var size = bounds.size var size = bounds.size
var origin = bounds.origin var origin = bounds.origin
size.height = 2/3 * size.height size.height = 2/3 * size.height
origin.y = 1/3 * bounds.size.height origin.y = 1/3 * bounds.size.height
if isDisclosureIndicatorVisible { if isDisclosureIndicatorVisible {
origin.x += CGFloat(UIAnimatedTextField.disclosureIndicatorWidth) origin.x += CGFloat(UIAnimatedTextField.disclosureIndicatorWidth)
size.width -= CGFloat(UIAnimatedTextField.disclosureIndicatorWidth) * 2 size.width -= CGFloat(UIAnimatedTextField.disclosureIndicatorWidth) * 2
} }
let textFieldBounds = CGRect(origin: origin, size: size) let textFieldBounds = CGRect(origin: origin, size: size)
return textFieldBounds return textFieldBounds
} }
private func placeholderLabelFrame(state: AnimatedTextFieldState) -> CGRect { private func placeholderLabelFrame(state: AnimatedTextFieldState) -> CGRect {
if state == .placeholder { if state == .placeholder {
return textFieldFrame() return textFieldFrame()
} else { } else {
var size = bounds.size var size = bounds.size
size.height = 1/3 * size.height size.height = 1/3 * size.height
let placeholderLabelBounds = CGRect(origin: bounds.origin, size: size) let placeholderLabelBounds = CGRect(origin: bounds.origin, size: size)
return placeholderLabelBounds return placeholderLabelBounds
} }
} }
private func disclosureIndicatorFrame() -> CGRect { private func disclosureIndicatorFrame() -> CGRect {
let fieldFrame = textFieldFrame() let fieldFrame = textFieldFrame()
let frame = CGRect(x: bounds.width - CGFloat(UIAnimatedTextField.disclosureIndicatorWidth), let frame = CGRect(x: bounds.width - CGFloat(UIAnimatedTextField.disclosureIndicatorWidth),
@ -296,7 +311,7 @@ public class UIAnimatedTextField: UIView {
height: fieldFrame.height) height: fieldFrame.height)
return frame return frame
} }
private func placeholderLabelTransform(state: AnimatedTextFieldState) -> CGAffineTransform { private func placeholderLabelTransform(state: AnimatedTextFieldState) -> CGAffineTransform {
if state == .placeholder { if state == .placeholder {
return CGAffineTransform.identity return CGAffineTransform.identity
@ -304,27 +319,27 @@ public class UIAnimatedTextField: UIView {
return CGAffineTransform(scaleX: 0.8, y: 0.8) return CGAffineTransform(scaleX: 0.8, y: 0.8)
} }
} }
override public func layoutSubviews() { override open func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
textField.frame = textFieldFrame() textField.frame = textFieldFrame()
if isDisclosureIndicatorVisible { if isDisclosureIndicatorVisible {
disclosureIndicatorImageView.frame = disclosureIndicatorFrame() disclosureIndicatorImageView.frame = disclosureIndicatorFrame()
} }
setState(toState: state, duration: 0) setState(toState: state, duration: 0)
lineView.frame = CGRect(x: 0, lineView.frame = CGRect(x: 0,
y: bounds.height - UIView.onePixelInPoints * 2, y: bounds.height - UIView.onePixelInPoints * 2,
width: bounds.width, width: bounds.width,
height: UIView.onePixelInPoints) height: UIView.onePixelInPoints)
} }
// MARK: - Animation // MARK: - Animation
public func setState(toState state: AnimatedTextFieldState, duration: TimeInterval) { public func setState(toState state: AnimatedTextFieldState, duration: TimeInterval = 0) {
UIView.animate( UIView.animate(
withDuration: duration, withDuration: duration,
delay: 0, delay: 0,
@ -333,9 +348,15 @@ public class UIAnimatedTextField: UIView {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
strongSelf.placeholderLabel.frame = strongSelf.placeholderLabelFrame(state: state) if strongSelf.isLeftTextAlignment {
strongSelf.placeholderLabel.transform = strongSelf.placeholderLabelTransform(state: state) 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 { switch state {
case .placeholder: case .placeholder:
strongSelf.placeholderLabel.textColor = strongSelf.placeholderBottomColor strongSelf.placeholderLabel.textColor = strongSelf.placeholderBottomColor
@ -345,50 +366,50 @@ public class UIAnimatedTextField: UIView {
}, },
completion: nil) completion: nil)
} }
// MARK: - Actions // MARK: - Actions
@objc private func tapGestureRecognizerAction(_ sender: UITapGestureRecognizer) { @objc private func tapGestureRecognizerAction(_ sender: UITapGestureRecognizer) {
delegate?.animatedTextFieldWillReactForTap?() delegate?.animatedTextFieldWillReactForTap?()
tapAction?(self) tapAction?(self)
} }
public func validateText() -> Bool { open func validateText() -> Bool {
guard let text = textField.text else { guard let text = textField.text else {
return false return false
} }
switch type { switch type {
case .url: case .url:
return text.isValidEmail return text.isValidEmail
default: default:
break break
} }
return true return true
} }
public func showInfo(infoText: String) { open func showInfo(infoText: String) {
guard !isShownInfo else { guard !isShownInfo else {
return return
} }
isShownInfo = true isShownInfo = true
let currentPlaceholder = placeholder let currentPlaceholder = placeholder
UIView.transition(with: placeholderLabel, UIView.transition(with: placeholderLabel,
duration: 0.5, duration: 0.5,
options: .transitionFlipFromTop, options: .transitionFlipFromTop,
animations: { [weak self] in animations: { [weak self] in
self?.placeholder = infoText self?.placeholder = infoText
}, completion: nil) }, completion: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { [weak self] in DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { [weak self] in
guard let placeholderLabel = self?.placeholderLabel else { guard let placeholderLabel = self?.placeholderLabel else {
return return
} }
UIView.transition(with: placeholderLabel, UIView.transition(with: placeholderLabel,
duration: 0.5, duration: 0.5,
options: .transitionFlipFromBottom, options: .transitionFlipFromBottom,
@ -399,120 +420,131 @@ public class UIAnimatedTextField: UIView {
}) })
} }
} }
// MARK: - Private // MARK: - Private
private func getDateInputView() -> UIDatePicker { private func getDateInputView() -> UIDatePicker {
let currentDate = Date() let currentDate = Date()
let datePicker = UIDatePicker() let datePicker = UIDatePicker()
datePicker.timeZone = TimeZone(secondsFromGMT: 0) datePicker.timeZone = TimeZone(secondsFromGMT: 0)
datePicker.datePickerMode = .date datePicker.datePickerMode = .date
datePicker.backgroundColor = UIColor.white datePicker.backgroundColor = UIColor.white
datePicker.setDate(currentDate, animated: true) datePicker.setDate(selectedDate ?? currentDate, animated: true)
datePicker.maximumDate = currentDate datePicker.maximumDate = currentDate
datePicker.addTarget(self, action: #selector(datePickerValueChanged(_:)), for: .valueChanged) datePicker.addTarget(self, action: #selector(datePickerValueChanged(_:)), for: .valueChanged)
return datePicker return datePicker
} }
@objc private func datePickerValueChanged(_ datePicker: UIDatePicker) { @objc private func datePickerValueChanged(_ datePicker: UIDatePicker) {
selectedDate = datePicker.date updateText(from: datePicker)
text = datePicker.date.toString(withFormat: dateFormat)
} }
private func getDateInputAccessoryView() -> UIView { private func getDateInputAccessoryView() -> UIView {
let toolbar = UIToolbar() let toolbar = UIToolbar()
toolbar.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 44) toolbar.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 44)
toolbar.autoresizingMask = [.flexibleWidth] toolbar.autoresizingMask = [.flexibleWidth]
toolbar.barTintColor = UIColor.white toolbar.barTintColor = UIColor.white
let spacerItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let spacerItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneItem = UIBarButtonItem(title: doneTitle, let doneItem = UIBarButtonItem(title: doneTitle,
style: .done, style: .done,
target: self, target: self,
action: #selector(datePickerDoneAction)) action: #selector(datePickerDoneAction))
let attributes = [ let attributes = [
NSForegroundColorAttributeName: UIColor.black NSAttributedString.Key.foregroundColor: doneTitleColor
] ]
doneItem.setTitleTextAttributes(attributes, for: .normal) doneItem.setTitleTextAttributes(attributes, for: .normal)
toolbar.items = [spacerItem, doneItem] toolbar.setItems([spacerItem, doneItem], animated: false)
return toolbar return toolbar
} }
fileprivate func updateText(from datePicker: UIDatePicker) {
selectedDate = datePicker.date
text = datePicker.date.toString(withFormat: dateFormat)
}
@objc private func datePickerDoneAction() { @objc private func datePickerDoneAction() {
if let datePicker = textField.inputView as? UIDatePicker {
updateText(from: datePicker)
}
textField.resignFirstResponder() textField.resignFirstResponder()
} }
@objc private func textFieldValueDidChange() { @objc private func textFieldValueDidChange() {
delegate?.animatedTextFieldValueDidChange?(self) delegate?.animatedTextFieldValueDidChange?(self)
} }
} }
// MARK: - Extension // MARK: - Extension
extension UIAnimatedTextField: UITextFieldDelegate { extension UIAnimatedTextField: UITextFieldDelegate {
public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { open func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
var result = true var result = true
if let delegateResult = delegate?.animatedTextFieldShouldBeginEditing?(self) { if let delegateResult = delegate?.animatedTextFieldShouldBeginEditing?(self) {
result = delegateResult result = delegateResult
} }
return result return result
} }
public func textFieldDidBeginEditing(_ textField: UITextField) { open func textFieldDidBeginEditing(_ textField: UITextField) {
if textField.text?.characters.count ?? 0 == 0 { if textField.text?.count ?? 0 == 0 {
setState(toState: .text, duration: UIAnimatedTextField.animationDuration) setState(toState: .text, duration: UIAnimatedTextField.animationDuration)
} }
if case .date = type { if case .date = type {
if let datePicker = textField.inputView as? UIDatePicker { if let datePicker = textField.inputView as? UIDatePicker {
textField.text = datePicker.date.toString(withFormat: dateFormat) textField.text = datePicker.date.toString(withFormat: dateFormat)
} }
} }
delegate?.animatedTextFieldDidBeginEditing?(self) delegate?.animatedTextFieldDidBeginEditing?(self)
} }
public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { open func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
var result = true var result = true
if let delegateResult = delegate?.animatedTextFieldShouldEndEditing?(self) { if let delegateResult = delegate?.animatedTextFieldShouldEndEditing?(self) {
result = delegateResult result = delegateResult
} }
return result return result
} }
public func textFieldDidEndEditing(_ textField: UITextField) { open func textFieldDidEndEditing(_ textField: UITextField) {
if textField.text?.characters.count ?? 0 == 0 { if textField.text?.count ?? 0 == 0 {
setState(toState: .placeholder, duration: UIAnimatedTextField.animationDuration) setState(toState: .placeholder, duration: UIAnimatedTextField.animationDuration)
} }
if let datePicker = textField.inputView as? UIDatePicker {
updateText(from: datePicker)
}
delegate?.animatedTextFieldDidEndEditing?(self) delegate?.animatedTextFieldDidEndEditing?(self)
} }
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, open func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool { replacementString string: String) -> Bool {
var result = true var result = true
if let delegateResult = delegate?.animatedTextField?(self, shouldChangeCharactersInRange: range, if let delegateResult = delegate?.animatedTextField?(self, shouldChangeCharactersInRange: range,
replacementString: string) { replacementString: string) {
result = delegateResult result = delegateResult
} }
if string == Constants.space { if string == Constants.space {
if textField.text?.isEmpty ?? true { if textField.text?.isEmpty ?? true {
result = false result = false
} }
switch type { switch type {
case .password, .url: case .password, .url:
result = false result = false
@ -520,28 +552,28 @@ extension UIAnimatedTextField: UITextFieldDelegate {
break break
} }
} }
return result return result
} }
public func textFieldShouldClear(_ textField: UITextField) -> Bool { open func textFieldShouldClear(_ textField: UITextField) -> Bool {
var result = true var result = true
if let delegateResult = delegate?.animatedTextFieldShouldClear?(self) { if let delegateResult = delegate?.animatedTextFieldShouldClear?(self) {
result = delegateResult result = delegateResult
} }
return result return result
} }
public func textFieldShouldReturn(_ textField: UITextField) -> Bool { open func textFieldShouldReturn(_ textField: UITextField) -> Bool {
var result = true var result = true
if let delegateResult = delegate?.animatedTextFieldShouldReturn?(self) { if let delegateResult = delegate?.animatedTextFieldShouldReturn?(self) {
result = delegateResult result = delegateResult
} }
return result return result
} }
} }