├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── Example
├── Podfile
├── Podfile.lock
├── Pods
│ ├── Local Podspecs
│ │ └── RAGTextField.podspec.json
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── RAGTextField.xcscheme
│ └── Target Support Files
│ │ ├── Pods-RAGTextField_Example
│ │ ├── Info.plist
│ │ ├── Pods-RAGTextField_Example-Info.plist
│ │ ├── Pods-RAGTextField_Example-acknowledgements.markdown
│ │ ├── Pods-RAGTextField_Example-acknowledgements.plist
│ │ ├── Pods-RAGTextField_Example-dummy.m
│ │ ├── Pods-RAGTextField_Example-frameworks.sh
│ │ ├── Pods-RAGTextField_Example-resources.sh
│ │ ├── Pods-RAGTextField_Example-umbrella.h
│ │ ├── Pods-RAGTextField_Example.debug.xcconfig
│ │ ├── Pods-RAGTextField_Example.modulemap
│ │ └── Pods-RAGTextField_Example.release.xcconfig
│ │ ├── Pods-RAGTextField_Tests
│ │ ├── Info.plist
│ │ ├── Pods-RAGTextField_Tests-Info.plist
│ │ ├── Pods-RAGTextField_Tests-acknowledgements.markdown
│ │ ├── Pods-RAGTextField_Tests-acknowledgements.plist
│ │ ├── Pods-RAGTextField_Tests-dummy.m
│ │ ├── Pods-RAGTextField_Tests-frameworks.sh
│ │ ├── Pods-RAGTextField_Tests-resources.sh
│ │ ├── Pods-RAGTextField_Tests-umbrella.h
│ │ ├── Pods-RAGTextField_Tests.debug.xcconfig
│ │ ├── Pods-RAGTextField_Tests.modulemap
│ │ └── Pods-RAGTextField_Tests.release.xcconfig
│ │ └── RAGTextField
│ │ ├── Info.plist
│ │ ├── RAGTextField-Info.plist
│ │ ├── RAGTextField-dummy.m
│ │ ├── RAGTextField-prefix.pch
│ │ ├── RAGTextField-umbrella.h
│ │ ├── RAGTextField.debug.xcconfig
│ │ ├── RAGTextField.modulemap
│ │ ├── RAGTextField.release.xcconfig
│ │ └── RAGTextField.xcconfig
├── RAGTextField.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── RAGTextField-Example.xcscheme
├── RAGTextField.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
├── RAGTextField
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── LaunchScreen.xib
│ │ └── Main.storyboard
│ ├── ColorPalette.swift
│ ├── Hint.storyboard
│ ├── HintViewController.swift
│ ├── Images.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── calendar.imageset
│ │ │ ├── Contents.json
│ │ │ ├── calendar@2x.png
│ │ │ └── calendar@3x.png
│ │ └── search.imageset
│ │ │ ├── Contents.json
│ │ │ ├── lupe@2x.png
│ │ │ └── lupe@3x.png
│ ├── Info.plist
│ ├── KeyboardEvader.swift
│ ├── LeftAndRightViews.storyboard
│ ├── LeftAndRightViewsViewController.swift
│ ├── Outline.storyboard
│ ├── OutlineViewController.swift
│ ├── Placeholder.storyboard
│ ├── PlaceholderViewController.swift
│ ├── TextAlignment.storyboard
│ ├── TextAlignmentViewController.swift
│ ├── TextPadding.storyboard
│ ├── TextPaddingViewController.swift
│ ├── UIColor+Hex.swift
│ ├── Underline.storyboard
│ ├── UnderlineViewController.swift
│ └── ViewController.swift
└── Tests
│ ├── Info.plist
│ └── Tests.swift
├── LICENSE
├── Package.swift
├── RAGTextField.podspec
├── README.md
├── Sources
└── RAGTextField
│ ├── Assets
│ └── .gitkeep
│ └── Classes
│ ├── .gitkeep
│ ├── Extensions
│ └── String+RAGTextField.swift
│ ├── PlaceholderView.swift
│ ├── RAGTextField.swift
│ ├── RAGTextFieldPlaceholderMode.swift
│ ├── RAGTextPaddingMode.swift
│ └── Views
│ ├── OutlineView.swift
│ └── UnderlineView.swift
└── _Pods.xcodeproj
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | .build/
41 |
42 | # CocoaPods
43 | #
44 | # We recommend against adding the Pods directory to your .gitignore. However
45 | # you should judge for yourself, the pros and cons are mentioned at:
46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
47 | #
48 | # Pods/
49 |
50 | # Carthage
51 | #
52 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
53 | # Carthage/Checkouts
54 |
55 | Carthage/Build
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
63 |
64 | fastlane/report.xml
65 | fastlane/Preview.html
66 | fastlane/screenshots
67 | fastlane/test_output
68 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # references:
2 | # * http://www.objc.io/issue-6/travis-ci.html
3 |
4 | os: osx
5 | osx_image: xcode10.2
6 | language: objective-c
7 |
8 | script:
9 | - set -o pipefail && xcodebuild test -workspace Example/RAGTextField.xcworkspace -scheme RAGTextField-Example -sdk iphonesimulator12.2 ONLY_ACTIVE_ARCH=NO | xcpretty
10 | - pod lib lint
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 |
4 | This project adheres to [Semantic Versioning](http://semver.org/).
5 |
6 | ## 0.14.0
7 |
8 | - Add support for Swift Package Manager
9 | - Add placeholder mode "scalesAlways" which always transforms the placeholder
10 |
11 | ## 0.13.0
12 |
13 | Updated to Swift 5.
14 |
15 | ## 0.12.1
16 |
17 | ### Fixed
18 | - Minor bugfix
19 |
20 | ## 0.12.0
21 |
22 | ### Added
23 | - Added support of multi-line hints.
24 |
25 | ## 0.11.0
26 |
27 | ### Added
28 | - Added property `transformedPlaceholderColor` that sets the placeholder color when the text field is being edited and the placeholder is in its floating position.
29 | - Added property `layoutAlwaysIncludesHint` that always keeps the hint label in the layout even if the `hint` is `nil`.
30 |
31 | ### Fixed
32 | - Fixed the resizing of the placeholder when its text or font are changed.
33 |
34 | ## 0.10.0
35 |
36 | After updating to this version, you may have to adjust the `placeholderMode` values of your text fields because the default placeholder mode has changed.
37 |
38 | ### Added
39 | - Added the `textField` property to the `UnderlineView`. If not `nil`, the underline updates its appearance in accordance with the editing state of the text field.
40 |
41 | ### Changed
42 | - The default placeholder mode has been changed from "when not empty" to "when editing".
43 |
44 | ## 0.9.1
45 |
46 | ### Fixed
47 | - Fixed placeholder animation on iOS 9
48 |
49 | ## 0.9.0
50 |
51 | ### Changed
52 | - Implemented a much more helpful example project for the pod. Please "try".
53 |
54 | ### Fixed
55 | - The horizontal text position would not be updated if the left or right views of the text field were shown or hidden
56 |
57 | ## 0.8.1
58 |
59 | ### Fixed
60 | - View performs a layout pass when the text padding mode is set
61 | - View no longer animates the placeholder when the text propert is set
62 |
63 | ## 0.8.0
64 |
65 | ### Changed
66 | - The height of the background line of the `UnderlineView` is always 1 pixel wide. The property `foregroundLineWidth` (formerly "lineWidth") affects the height of the foreground line only (API breaking change).
67 |
68 | ### Fixed
69 | - Fixed default placeholder color
70 | - Fixed initial placeholder text alignment
71 |
72 | ## 0.7.0
73 |
74 | ### Added
75 | - Added property `textPaddingMode`. Used to apply the `textPadding` to just the text, or in addition to that to the placeholder, the hint or both.
76 |
77 | ## 0.6.1
78 |
79 | ### Fixed
80 | - Fixed horizontal intrinsic content size
81 |
82 | ## 0.6.0
83 |
84 | ### Changed
85 | - Replaced `horizontalTextPadding` and `verticalTextPadding` with `textPadding` of type `UIEdgeInsets` (API breaking change). Values can be set in IB.
86 |
87 | ## 0.5.0
88 |
89 | ### Added
90 | - Added optional vertical `hintOffset` of the hint label to the bottom of the text
91 | - Added Carthage support
92 |
93 | ## 0.4.0
94 |
95 | Pretty much redid the whole thing. There should be no API-breaking changes.
96 |
97 | ### Added
98 | - Added support for right-to-left languages
99 | - Added support for the left and right views
100 | - Added `UnderlineView` that can be used with the text view
101 |
102 | ### Changed
103 | - Updated to Swift 4
104 | - Improved handling of text alignments
105 | - Improved documentation
106 | - Bugfixes
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '9.0'
2 |
3 | use_frameworks!
4 |
5 | target 'RAGTextField_Example' do
6 | pod 'RAGTextField', :path => '../'
7 |
8 | target 'RAGTextField_Tests' do
9 | inherit! :search_paths
10 |
11 |
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/Example/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - RAGTextField (0.13.0)
3 |
4 | DEPENDENCIES:
5 | - RAGTextField (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | RAGTextField:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | RAGTextField: 5a94e334dba9bd1ce49cecb52e660026ca66de19
13 |
14 | PODFILE CHECKSUM: 49ab1e44f0e4c093a292143cccd721727174919d
15 |
16 | COCOAPODS: 1.9.3
17 |
--------------------------------------------------------------------------------
/Example/Pods/Local Podspecs/RAGTextField.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "RAGTextField",
3 | "version": "0.13.0",
4 | "summary": "Subclass of UITextField featuring a floating placeholder and a hint label.",
5 | "description": "Subclass of UITextField that adds an animated placeholder and an optional hint label below the text. Supports an arbitrary view in the background of the text (outline and underline views are provided) as well as the left and right views, text alignments, flexible padding and offsets.",
6 | "homepage": "https://github.com/raginmari/RAGTextField",
7 | "license": {
8 | "type": "MIT",
9 | "file": "LICENSE"
10 | },
11 | "authors": {
12 | "raginmari": "reimar.twelker@web.de"
13 | },
14 | "source": {
15 | "git": "https://github.com/raginmari/RAGTextField.git",
16 | "tag": "0.13.0"
17 | },
18 | "platforms": {
19 | "ios": "9.0"
20 | },
21 | "swift_versions": "5.0",
22 | "source_files": "Sources/RAGTextField/Classes/**/*",
23 | "swift_version": "5.0"
24 | }
25 |
--------------------------------------------------------------------------------
/Example/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - RAGTextField (0.13.0)
3 |
4 | DEPENDENCIES:
5 | - RAGTextField (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | RAGTextField:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | RAGTextField: 5a94e334dba9bd1ce49cecb52e660026ca66de19
13 |
14 | PODFILE CHECKSUM: 49ab1e44f0e4c093a292143cccd721727174919d
15 |
16 | COCOAPODS: 1.9.3
17 |
--------------------------------------------------------------------------------
/Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/RAGTextField.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
66 |
67 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Example/Pods-RAGTextField_Example-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Example/Pods-RAGTextField_Example-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## RAGTextField
5 |
6 | Copyright (c) 2017 raginmari
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | Generated by CocoaPods - https://cocoapods.org
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Example/Pods-RAGTextField_Example-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Copyright (c) 2017 raginmari <reimar.twelker@web.de>
18 |
19 | Permission is hereby granted, free of charge, to any person obtaining a copy
20 | of this software and associated documentation files (the "Software"), to deal
21 | in the Software without restriction, including without limitation the rights
22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 | copies of the Software, and to permit persons to whom the Software is
24 | furnished to do so, subject to the following conditions:
25 |
26 | The above copyright notice and this permission notice shall be included in
27 | all copies or substantial portions of the Software.
28 |
29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 | THE SOFTWARE.
36 |
37 | License
38 | MIT
39 | Title
40 | RAGTextField
41 | Type
42 | PSGroupSpecifier
43 |
44 |
45 | FooterText
46 | Generated by CocoaPods - https://cocoapods.org
47 | Title
48 |
49 | Type
50 | PSGroupSpecifier
51 |
52 |
53 | StringsTable
54 | Acknowledgements
55 | Title
56 | Acknowledgements
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Example/Pods-RAGTextField_Example-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_RAGTextField_Example : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_RAGTextField_Example
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Example/Pods-RAGTextField_Example-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 | # frameworks to, so exit 0 (signalling the script phase was successful).
14 | exit 0
15 | fi
16 |
17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19 |
20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 |
23 | # Used as a return value for each invocation of `strip_invalid_archs` function.
24 | STRIP_BINARY_RETVAL=0
25 |
26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
29 |
30 | # Copies and strips a vendored framework
31 | install_framework()
32 | {
33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
34 | local source="${BUILT_PRODUCTS_DIR}/$1"
35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
37 | elif [ -r "$1" ]; then
38 | local source="$1"
39 | fi
40 |
41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
42 |
43 | if [ -L "${source}" ]; then
44 | echo "Symlinked..."
45 | source="$(readlink "${source}")"
46 | fi
47 |
48 | # Use filter instead of exclude so missing patterns don't throw errors.
49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
51 |
52 | local basename
53 | basename="$(basename -s .framework "$1")"
54 | binary="${destination}/${basename}.framework/${basename}"
55 |
56 | if ! [ -r "$binary" ]; then
57 | binary="${destination}/${basename}"
58 | elif [ -L "${binary}" ]; then
59 | echo "Destination binary is symlinked..."
60 | dirname="$(dirname "${binary}")"
61 | binary="${dirname}/$(readlink "${binary}")"
62 | fi
63 |
64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
66 | strip_invalid_archs "$binary"
67 | fi
68 |
69 | # Resign the code if required by the build settings to avoid unstable apps
70 | code_sign_if_enabled "${destination}/$(basename "$1")"
71 |
72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
74 | local swift_runtime_libs
75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
76 | for lib in $swift_runtime_libs; do
77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
79 | code_sign_if_enabled "${destination}/${lib}"
80 | done
81 | fi
82 | }
83 |
84 | # Copies and strips a vendored dSYM
85 | install_dsym() {
86 | local source="$1"
87 | warn_missing_arch=${2:-true}
88 | if [ -r "$source" ]; then
89 | # Copy the dSYM into the targets temp dir.
90 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
91 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
92 |
93 | local basename
94 | basename="$(basename -s .dSYM "$source")"
95 | binary_name="$(ls "$source/Contents/Resources/DWARF")"
96 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
97 |
98 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
99 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
100 | strip_invalid_archs "$binary" "$warn_missing_arch"
101 | fi
102 |
103 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
104 | # Move the stripped file into its final destination.
105 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
106 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
107 | else
108 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
109 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
110 | fi
111 | fi
112 | }
113 |
114 | # Copies the bcsymbolmap files of a vendored framework
115 | install_bcsymbolmap() {
116 | local bcsymbolmap_path="$1"
117 | local destination="${BUILT_PRODUCTS_DIR}"
118 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
119 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
120 | }
121 |
122 | # Signs a framework with the provided identity
123 | code_sign_if_enabled() {
124 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
125 | # Use the current code_sign_identity
126 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
127 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
128 |
129 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
130 | code_sign_cmd="$code_sign_cmd &"
131 | fi
132 | echo "$code_sign_cmd"
133 | eval "$code_sign_cmd"
134 | fi
135 | }
136 |
137 | # Strip invalid architectures
138 | strip_invalid_archs() {
139 | binary="$1"
140 | warn_missing_arch=${2:-true}
141 | # Get architectures for current target binary
142 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
143 | # Intersect them with the architectures we are building for
144 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
145 | # If there are no archs supported by this binary then warn the user
146 | if [[ -z "$intersected_archs" ]]; then
147 | if [[ "$warn_missing_arch" == "true" ]]; then
148 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
149 | fi
150 | STRIP_BINARY_RETVAL=0
151 | return
152 | fi
153 | stripped=""
154 | for arch in $binary_archs; do
155 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
156 | # Strip non-valid architectures in-place
157 | lipo -remove "$arch" -output "$binary" "$binary"
158 | stripped="$stripped $arch"
159 | fi
160 | done
161 | if [[ "$stripped" ]]; then
162 | echo "Stripped $binary of architectures:$stripped"
163 | fi
164 | STRIP_BINARY_RETVAL=1
165 | }
166 |
167 | install_artifact() {
168 | artifact="$1"
169 | base="$(basename "$artifact")"
170 | case $base in
171 | *.framework)
172 | install_framework "$artifact"
173 | ;;
174 | *.dSYM)
175 | # Suppress arch warnings since XCFrameworks will include many dSYM files
176 | install_dsym "$artifact" "false"
177 | ;;
178 | *.bcsymbolmap)
179 | install_bcsymbolmap "$artifact"
180 | ;;
181 | *)
182 | echo "error: Unrecognized artifact "$artifact""
183 | ;;
184 | esac
185 | }
186 |
187 | copy_artifacts() {
188 | file_list="$1"
189 | while read artifact; do
190 | install_artifact "$artifact"
191 | done <$file_list
192 | }
193 |
194 | ARTIFACT_LIST_FILE="${BUILT_PRODUCTS_DIR}/cocoapods-artifacts-${CONFIGURATION}.txt"
195 | if [ -r "${ARTIFACT_LIST_FILE}" ]; then
196 | copy_artifacts "${ARTIFACT_LIST_FILE}"
197 | fi
198 |
199 | if [[ "$CONFIGURATION" == "Debug" ]]; then
200 | install_framework "${BUILT_PRODUCTS_DIR}/RAGTextField/RAGTextField.framework"
201 | fi
202 | if [[ "$CONFIGURATION" == "Release" ]]; then
203 | install_framework "${BUILT_PRODUCTS_DIR}/RAGTextField/RAGTextField.framework"
204 | fi
205 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
206 | wait
207 | fi
208 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Example/Pods-RAGTextField_Example-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
5 |
6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
7 | > "$RESOURCES_TO_COPY"
8 |
9 | XCASSET_FILES=()
10 |
11 | case "${TARGETED_DEVICE_FAMILY}" in
12 | 1,2)
13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
14 | ;;
15 | 1)
16 | TARGET_DEVICE_ARGS="--target-device iphone"
17 | ;;
18 | 2)
19 | TARGET_DEVICE_ARGS="--target-device ipad"
20 | ;;
21 | *)
22 | TARGET_DEVICE_ARGS="--target-device mac"
23 | ;;
24 | esac
25 |
26 | install_resource()
27 | {
28 | if [[ "$1" = /* ]] ; then
29 | RESOURCE_PATH="$1"
30 | else
31 | RESOURCE_PATH="${PODS_ROOT}/$1"
32 | fi
33 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
34 | cat << EOM
35 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
36 | EOM
37 | exit 1
38 | fi
39 | case $RESOURCE_PATH in
40 | *.storyboard)
41 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
42 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
43 | ;;
44 | *.xib)
45 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
46 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
47 | ;;
48 | *.framework)
49 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
50 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
51 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
52 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
53 | ;;
54 | *.xcdatamodel)
55 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
56 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
57 | ;;
58 | *.xcdatamodeld)
59 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
60 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
61 | ;;
62 | *.xcmappingmodel)
63 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
64 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
65 | ;;
66 | *.xcassets)
67 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
68 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
69 | ;;
70 | *)
71 | echo "$RESOURCE_PATH"
72 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
73 | ;;
74 | esac
75 | }
76 |
77 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
78 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
79 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
80 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
81 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
82 | fi
83 | rm -f "$RESOURCES_TO_COPY"
84 |
85 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
86 | then
87 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
88 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
89 | while read line; do
90 | if [[ $line != "${PODS_ROOT}*" ]]; then
91 | XCASSET_FILES+=("$line")
92 | fi
93 | done <<<"$OTHER_XCASSETS"
94 |
95 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
96 | fi
97 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Example/Pods-RAGTextField_Example-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_RAGTextField_ExampleVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_RAGTextField_ExampleVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Example/Pods-RAGTextField_Example.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RAGTextField"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RAGTextField/RAGTextField.framework/Headers"
5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 | OTHER_LDFLAGS = $(inherited) -framework "RAGTextField"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Example/Pods-RAGTextField_Example.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_RAGTextField_Example {
2 | umbrella header "Pods-RAGTextField_Example-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Example/Pods-RAGTextField_Example.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RAGTextField"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RAGTextField/RAGTextField.framework/Headers"
5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 | OTHER_LDFLAGS = $(inherited) -framework "RAGTextField"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Tests/Pods-RAGTextField_Tests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Tests/Pods-RAGTextField_Tests-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 | Generated by CocoaPods - https://cocoapods.org
4 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Tests/Pods-RAGTextField_Tests-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Generated by CocoaPods - https://cocoapods.org
18 | Title
19 |
20 | Type
21 | PSGroupSpecifier
22 |
23 |
24 | StringsTable
25 | Acknowledgements
26 | Title
27 | Acknowledgements
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Tests/Pods-RAGTextField_Tests-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_RAGTextField_Tests : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_RAGTextField_Tests
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Tests/Pods-RAGTextField_Tests-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
6 |
7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
8 |
9 | install_framework()
10 | {
11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
12 | local source="${BUILT_PRODUCTS_DIR}/$1"
13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
15 | elif [ -r "$1" ]; then
16 | local source="$1"
17 | fi
18 |
19 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
20 |
21 | if [ -L "${source}" ]; then
22 | echo "Symlinked..."
23 | source="$(readlink "${source}")"
24 | fi
25 |
26 | # use filter instead of exclude so missing patterns dont' throw errors
27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
29 |
30 | local basename
31 | basename="$(basename -s .framework "$1")"
32 | binary="${destination}/${basename}.framework/${basename}"
33 | if ! [ -r "$binary" ]; then
34 | binary="${destination}/${basename}"
35 | fi
36 |
37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
39 | strip_invalid_archs "$binary"
40 | fi
41 |
42 | # Resign the code if required by the build settings to avoid unstable apps
43 | code_sign_if_enabled "${destination}/$(basename "$1")"
44 |
45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
47 | local swift_runtime_libs
48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
49 | for lib in $swift_runtime_libs; do
50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
52 | code_sign_if_enabled "${destination}/${lib}"
53 | done
54 | fi
55 | }
56 |
57 | # Signs a framework with the provided identity
58 | code_sign_if_enabled() {
59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
60 | # Use the current code_sign_identitiy
61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
62 | echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
63 | /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
64 | fi
65 | }
66 |
67 | # Strip invalid architectures
68 | strip_invalid_archs() {
69 | binary="$1"
70 | # Get architectures for current file
71 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
72 | stripped=""
73 | for arch in $archs; do
74 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
75 | # Strip non-valid architectures in-place
76 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1
77 | stripped="$stripped $arch"
78 | fi
79 | done
80 | if [[ "$stripped" ]]; then
81 | echo "Stripped $binary of architectures:$stripped"
82 | fi
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Tests/Pods-RAGTextField_Tests-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
5 |
6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
7 | > "$RESOURCES_TO_COPY"
8 |
9 | XCASSET_FILES=()
10 |
11 | case "${TARGETED_DEVICE_FAMILY}" in
12 | 1,2)
13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
14 | ;;
15 | 1)
16 | TARGET_DEVICE_ARGS="--target-device iphone"
17 | ;;
18 | 2)
19 | TARGET_DEVICE_ARGS="--target-device ipad"
20 | ;;
21 | *)
22 | TARGET_DEVICE_ARGS="--target-device mac"
23 | ;;
24 | esac
25 |
26 | install_resource()
27 | {
28 | if [[ "$1" = /* ]] ; then
29 | RESOURCE_PATH="$1"
30 | else
31 | RESOURCE_PATH="${PODS_ROOT}/$1"
32 | fi
33 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
34 | cat << EOM
35 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
36 | EOM
37 | exit 1
38 | fi
39 | case $RESOURCE_PATH in
40 | *.storyboard)
41 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
42 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
43 | ;;
44 | *.xib)
45 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
46 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
47 | ;;
48 | *.framework)
49 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
50 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
51 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
52 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
53 | ;;
54 | *.xcdatamodel)
55 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
56 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
57 | ;;
58 | *.xcdatamodeld)
59 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
60 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
61 | ;;
62 | *.xcmappingmodel)
63 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
64 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
65 | ;;
66 | *.xcassets)
67 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
68 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
69 | ;;
70 | *)
71 | echo "$RESOURCE_PATH"
72 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
73 | ;;
74 | esac
75 | }
76 |
77 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
78 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
79 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
80 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
81 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
82 | fi
83 | rm -f "$RESOURCES_TO_COPY"
84 |
85 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
86 | then
87 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
88 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
89 | while read line; do
90 | if [[ $line != "${PODS_ROOT}*" ]]; then
91 | XCASSET_FILES+=("$line")
92 | fi
93 | done <<<"$OTHER_XCASSETS"
94 |
95 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
96 | fi
97 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Tests/Pods-RAGTextField_Tests-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_RAGTextField_TestsVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_RAGTextField_TestsVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Tests/Pods-RAGTextField_Tests.debug.xcconfig:
--------------------------------------------------------------------------------
1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RAGTextField"
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RAGTextField/RAGTextField.framework/Headers"
4 | OTHER_LDFLAGS = $(inherited) -framework "RAGTextField"
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
8 | PODS_ROOT = ${SRCROOT}/Pods
9 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
10 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Tests/Pods-RAGTextField_Tests.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_RAGTextField_Tests {
2 | umbrella header "Pods-RAGTextField_Tests-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-RAGTextField_Tests/Pods-RAGTextField_Tests.release.xcconfig:
--------------------------------------------------------------------------------
1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RAGTextField"
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RAGTextField/RAGTextField.framework/Headers"
4 | OTHER_LDFLAGS = $(inherited) -framework "RAGTextField"
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
8 | PODS_ROOT = ${SRCROOT}/Pods
9 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
10 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/RAGTextField/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 0.1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/RAGTextField/RAGTextField-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 0.13.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/RAGTextField/RAGTextField-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_RAGTextField : NSObject
3 | @end
4 | @implementation PodsDummy_RAGTextField
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/RAGTextField/RAGTextField-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/RAGTextField/RAGTextField-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double RAGTextFieldVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char RAGTextFieldVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/RAGTextField/RAGTextField.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/RAGTextField
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
4 | PODS_BUILD_DIR = ${BUILD_DIR}
5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
6 | PODS_ROOT = ${SRCROOT}
7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
9 | SKIP_INSTALL = YES
10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
11 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/RAGTextField/RAGTextField.modulemap:
--------------------------------------------------------------------------------
1 | framework module RAGTextField {
2 | umbrella header "RAGTextField-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/RAGTextField/RAGTextField.release.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/RAGTextField
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
4 | PODS_BUILD_DIR = ${BUILD_DIR}
5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
6 | PODS_ROOT = ${SRCROOT}
7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
9 | SKIP_INSTALL = YES
10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
11 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/RAGTextField/RAGTextField.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/RAGTextField
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
4 | PODS_BUILD_DIR = ${BUILD_DIR}
5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
6 | PODS_ROOT = ${SRCROOT}
7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
9 | SKIP_INSTALL = YES
10 |
--------------------------------------------------------------------------------
/Example/RAGTextField.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/RAGTextField.xcodeproj/xcshareddata/xcschemes/RAGTextField-Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
65 |
66 |
67 |
68 |
78 |
80 |
86 |
87 |
88 |
89 |
90 |
91 |
97 |
99 |
105 |
106 |
107 |
108 |
110 |
111 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/Example/RAGTextField.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Example/RAGTextField.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/RAGTextField.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Example/RAGTextField/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @UIApplicationMain
4 | class AppDelegate: UIResponder, UIApplicationDelegate {
5 |
6 | var window: UIWindow?
7 |
8 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
9 | return true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Example/RAGTextField/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Example/RAGTextField/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/Example/RAGTextField/ColorPalette.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | enum ColorPalette {
4 |
5 | static let chalk = UIColor(hex: 0xECF0F1)
6 | static let flame = UIColor(hex: 0xE74C3C)
7 | static let sky = UIColor(hex: 0x3498DB)
8 | static let meadow = UIColor(hex: 0x2ECC71)
9 | static let savanna = UIColor(hex: 0xE67E22)
10 | static let bramble = UIColor(hex: 0x9B59B6)
11 | static let midnight = UIColor(hex: 0x34495E)
12 | static let stone = UIColor(hex: 0x95A5A6)
13 | static let star = UIColor(hex: 0xF1C40F)
14 | }
15 |
--------------------------------------------------------------------------------
/Example/RAGTextField/Hint.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/Example/RAGTextField/HintViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import RAGTextField
3 |
4 | final class HintViewController: UIViewController, UITextFieldDelegate {
5 |
6 | @IBOutlet private weak var hintTextField: RAGTextField! {
7 | didSet {
8 | setUp(hintTextField)
9 | hintTextField.hintColor = .darkGray
10 | hintTextField.hintFont = UIFont.systemFont(ofSize: 10.0)
11 | hintTextField.hint = "An info or error message"
12 | }
13 | }
14 |
15 | @IBOutlet private weak var coloredHintTextField: RAGTextField! {
16 | didSet {
17 | setUp(coloredHintTextField)
18 | coloredHintTextField.hintColor = ColorPalette.flame
19 | coloredHintTextField.hintFont = UIFont.systemFont(ofSize: 10.0)
20 | coloredHintTextField.hintOffset = 2.0
21 | coloredHintTextField.hint = "A password should contain at least 10 characters including lowercase and uppercase letters, digits and symbols. Hints should support multiple lines of text."
22 | }
23 | }
24 |
25 | @IBOutlet private weak var offsetHintTextField: RAGTextField! {
26 | didSet {
27 | setUp(offsetHintTextField)
28 | offsetHintTextField.hintColor = ColorPalette.sky
29 | offsetHintTextField.hintFont = UIFont.systemFont(ofSize: 11.0)
30 | offsetHintTextField.hint = "Keep a distance"
31 | }
32 | }
33 |
34 | @IBOutlet private weak var hintVisibilityControl: UISegmentedControl! {
35 | didSet {
36 | hintVisibilityControl.tintColor = .darkGray
37 | }
38 | }
39 |
40 | @IBOutlet private weak var hintOffsetControl: UISegmentedControl! {
41 | didSet {
42 | hintOffsetControl.tintColor = ColorPalette.sky
43 | }
44 | }
45 |
46 | private func setUp(_ textField: RAGTextField) {
47 |
48 | textField.delegate = self
49 | textField.textColor = ColorPalette.midnight
50 | textField.tintColor = ColorPalette.midnight
51 | textField.textBackgroundView = makeTextBackgroundView()
52 | textField.textPadding = UIEdgeInsets(top: 4.0, left: 4.0, bottom: 4.0, right: 4.0)
53 | textField.textPaddingMode = .textAndPlaceholderAndHint
54 | textField.scaledPlaceholderOffset = 2.0
55 | textField.placeholderMode = .scalesWhenEditing
56 | textField.placeholderScaleWhenEditing = 0.8
57 | textField.placeholderColor = ColorPalette.stone
58 | }
59 |
60 | private func makeTextBackgroundView() -> UIView {
61 |
62 | let view = UIView()
63 | view.layer.cornerRadius = 4.0
64 | view.backgroundColor = ColorPalette.chalk
65 |
66 | return view
67 | }
68 |
69 | override func viewDidLoad() {
70 |
71 | title = "Hint label"
72 |
73 | super.viewDidLoad()
74 |
75 | setHintVisibility(at: hintVisibilityControl.selectedSegmentIndex)
76 | setHintOffset(at: hintOffsetControl.selectedSegmentIndex)
77 | }
78 |
79 | @IBAction func onHintVisibilityDidChange(_ control: UISegmentedControl) {
80 |
81 | setHintVisibility(at: control.selectedSegmentIndex)
82 | }
83 |
84 | @IBAction func onHintOffsetDidChange(_ control: UISegmentedControl) {
85 |
86 | setHintOffset(at: control.selectedSegmentIndex)
87 | }
88 |
89 | private func setHintVisibility(at index: Int) {
90 |
91 | _ = hintTextField.resignFirstResponder()
92 |
93 | let value: String? = ["An info or error message", "", nil, nil][index]
94 | hintTextField.hint = value
95 |
96 | if index == 3 {
97 | hintTextField.layoutAlwaysIncludesHint = true
98 | } else {
99 | hintTextField.layoutAlwaysIncludesHint = false
100 | }
101 | }
102 |
103 | private func setHintOffset(at index: Int) {
104 |
105 | _ = offsetHintTextField.resignFirstResponder()
106 |
107 | let offset: CGFloat = [0.0, 8.0, 16.0][index]
108 | offsetHintTextField.hintOffset = offset
109 | }
110 |
111 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
112 |
113 | textField.resignFirstResponder()
114 |
115 | return false
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/Example/RAGTextField/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ios-marketing",
45 | "size" : "1024x1024",
46 | "scale" : "1x"
47 | }
48 | ],
49 | "info" : {
50 | "version" : 1,
51 | "author" : "xcode"
52 | }
53 | }
--------------------------------------------------------------------------------
/Example/RAGTextField/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/RAGTextField/Images.xcassets/calendar.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "calendar@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "calendar@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | },
22 | "properties" : {
23 | "template-rendering-intent" : "template"
24 | }
25 | }
--------------------------------------------------------------------------------
/Example/RAGTextField/Images.xcassets/calendar.imageset/calendar@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raginmari/RAGTextField/9a4b1237aed03e365931887d18b7398bc477df26/Example/RAGTextField/Images.xcassets/calendar.imageset/calendar@2x.png
--------------------------------------------------------------------------------
/Example/RAGTextField/Images.xcassets/calendar.imageset/calendar@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raginmari/RAGTextField/9a4b1237aed03e365931887d18b7398bc477df26/Example/RAGTextField/Images.xcassets/calendar.imageset/calendar@3x.png
--------------------------------------------------------------------------------
/Example/RAGTextField/Images.xcassets/search.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "lupe@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "lupe@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | },
22 | "properties" : {
23 | "template-rendering-intent" : "template"
24 | }
25 | }
--------------------------------------------------------------------------------
/Example/RAGTextField/Images.xcassets/search.imageset/lupe@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raginmari/RAGTextField/9a4b1237aed03e365931887d18b7398bc477df26/Example/RAGTextField/Images.xcassets/search.imageset/lupe@2x.png
--------------------------------------------------------------------------------
/Example/RAGTextField/Images.xcassets/search.imageset/lupe@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raginmari/RAGTextField/9a4b1237aed03e365931887d18b7398bc477df26/Example/RAGTextField/Images.xcassets/search.imageset/lupe@3x.png
--------------------------------------------------------------------------------
/Example/RAGTextField/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Example/RAGTextField/KeyboardEvader.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | final class KeyboardEvader: NSObject {
4 |
5 | @IBOutlet private weak var scrollView: UIScrollView?
6 |
7 | override func awakeFromNib() {
8 |
9 | super.awakeFromNib()
10 |
11 | registerForKeyboardNotifications()
12 | }
13 |
14 | private func registerForKeyboardNotifications() {
15 |
16 | NotificationCenter.default.addObserver(self,
17 | selector: #selector(onShowKeyboard(_:)),
18 | name: UIResponder.keyboardWillShowNotification,
19 | object: nil)
20 |
21 | NotificationCenter.default.addObserver(self,
22 | selector: #selector(onHideKeyboard(_:)),
23 | name: UIResponder.keyboardWillHideNotification,
24 | object: nil)
25 | }
26 |
27 | @objc private func onShowKeyboard(_ notification: Notification) {
28 |
29 | guard let scrollView = scrollView else { return }
30 | guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
31 |
32 | let insets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardFrame.height, right: 0)
33 | scrollView.contentInset = insets
34 | scrollView.scrollIndicatorInsets = insets
35 | }
36 |
37 | @objc private func onHideKeyboard(_ notification: Notification) {
38 |
39 | guard let scrollView = scrollView else { return }
40 | scrollView.contentInset = .zero
41 | scrollView.scrollIndicatorInsets = .zero
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Example/RAGTextField/LeftAndRightViewsViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import RAGTextField
3 |
4 | private enum Constants {
5 |
6 | static let leftAndRightViewTintColor = ColorPalette.flame
7 | }
8 |
9 | final class LeftAndRightViewsViewController: UIViewController, UITextFieldDelegate {
10 |
11 | @IBOutlet private weak var notificationView: UIView!
12 | @IBOutlet private weak var notificationLabel: UILabel!
13 |
14 | @IBOutlet private weak var leftViewSwitch: UISwitch! {
15 | didSet {
16 | leftViewSwitch.tintColor = Constants.leftAndRightViewTintColor
17 | leftViewSwitch.onTintColor = Constants.leftAndRightViewTintColor
18 | }
19 | }
20 |
21 | @IBOutlet private weak var leftViewModeControl: UISegmentedControl! {
22 | didSet {
23 | leftViewModeControl.tintColor = Constants.leftAndRightViewTintColor
24 | }
25 | }
26 |
27 | @IBOutlet private weak var rightViewSwitch: UISwitch! {
28 | didSet {
29 | rightViewSwitch.tintColor = Constants.leftAndRightViewTintColor
30 | rightViewSwitch.onTintColor = Constants.leftAndRightViewTintColor
31 | }
32 | }
33 |
34 | @IBOutlet private weak var rightViewModeControl: UISegmentedControl! {
35 | didSet {
36 | rightViewModeControl.tintColor = Constants.leftAndRightViewTintColor
37 | }
38 | }
39 |
40 | @IBOutlet private weak var leftViewTextField: RAGTextField! {
41 | didSet {
42 | setUp(leftViewTextField)
43 |
44 | leftViewTextField.placeholderMode = .simple
45 | leftViewTextField.placeholderColor = ColorPalette.stone
46 | leftViewTextField.leftView = makeSearchIconView()
47 | leftViewTextField.leftViewMode = .always
48 | leftViewTextField.textColor = ColorPalette.midnight
49 | leftViewTextField.tintColor = ColorPalette.stone
50 | leftViewTextField.hintFont = UIFont.systemFont(ofSize: 11.0)
51 | leftViewTextField.hintColor = ColorPalette.savanna
52 | leftViewTextField.hintOffset = 4.0
53 | leftViewTextField.hint = "Left view mode is .always"
54 | }
55 | }
56 |
57 | @IBOutlet private weak var rightViewTextField: RAGTextField! {
58 | didSet {
59 | setUp(rightViewTextField)
60 |
61 | rightViewTextField.placeholderMode = .scalesWhenEditing
62 | rightViewTextField.placeholderColor = ColorPalette.stone
63 | rightViewTextField.rightView = makeCalendarButtonView()
64 | rightViewTextField.rightViewMode = .unlessEditing
65 | rightViewTextField.textColor = ColorPalette.midnight
66 | rightViewTextField.tintColor = ColorPalette.stone
67 | rightViewTextField.hintFont = UIFont.systemFont(ofSize: 11.0)
68 | rightViewTextField.hintColor = ColorPalette.bramble
69 | rightViewTextField.hintOffset = 2.0
70 | rightViewTextField.hint = "Right view mode is .unlessEditing"
71 | }
72 | }
73 |
74 | @IBOutlet private weak var leftAndRightViewTextField: RAGTextField! {
75 | didSet {
76 | setUp(leftAndRightViewTextField, color: Constants.leftAndRightViewTintColor)
77 | leftAndRightViewTextField.placeholderMode = .scalesWhenEditing
78 | leftAndRightViewTextField.placeholderColor = ColorPalette.chalk
79 | leftAndRightViewTextField.textColor = .white
80 | leftAndRightViewTextField.tintColor = ColorPalette.chalk
81 | }
82 | }
83 |
84 | @IBOutlet private weak var uiTextField: UITextField! {
85 | didSet {
86 | uiTextField.delegate = self
87 | uiTextField.tintColor = ColorPalette.stone
88 | }
89 | }
90 |
91 | private func setUp(_ textField: RAGTextField, color: UIColor = ColorPalette.chalk) {
92 |
93 | textField.delegate = self
94 | textField.textBackgroundView = makeTextBackgroundView(color: color)
95 | textField.textPadding = UIEdgeInsets(top: 8.0, left: 8.0, bottom: 8.0, right: 8.0)
96 | textField.textPaddingMode = .textAndPlaceholderAndHint
97 | textField.scaledPlaceholderOffset = 2.0
98 | textField.placeholderScaleWhenEditing = 0.8
99 | }
100 |
101 | private func makeTextBackgroundView(color: UIColor) -> UIView {
102 |
103 | let view = UIView()
104 | view.layer.cornerRadius = 4.0
105 | view.backgroundColor = color
106 |
107 | return view
108 | }
109 |
110 | private func makeSearchIconView() -> UIView {
111 |
112 | return UIImageView(image: UIImage(named: "search"))
113 | }
114 |
115 | private func makeCalendarButtonView() -> UIView {
116 |
117 | let image = UIImage(named: "calendar")!
118 |
119 | let button = UIButton(type: .custom)
120 | button.setImage(image, for: .normal)
121 | button.frame = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
122 | button.addTarget(self, action: #selector(onCalendarButtonTapped(_:)), for: .touchUpInside)
123 |
124 | return button
125 | }
126 |
127 | @objc private func onCalendarButtonTapped(_ button: UIButton) {
128 |
129 | showNotification("Right view tapped")
130 | }
131 |
132 | override func viewDidLoad() {
133 |
134 | title = "Left and right views"
135 |
136 | setLeftView(visible: leftViewSwitch.isOn)
137 | setLeftViewMode(at: leftViewModeControl.selectedSegmentIndex)
138 |
139 | setRightView(visible: rightViewSwitch.isOn)
140 | setRightViewMode(at: rightViewModeControl.selectedSegmentIndex)
141 |
142 | super.viewDidLoad()
143 | }
144 |
145 | private func setLeftView(visible: Bool) {
146 |
147 | if visible {
148 | leftAndRightViewTextField.leftView = makeSearchIconView()
149 | uiTextField.leftView = makeSearchIconView()
150 | } else {
151 | leftAndRightViewTextField.leftView = nil
152 | uiTextField.leftView = nil
153 | }
154 | }
155 |
156 | private func setRightView(visible: Bool) {
157 |
158 | if visible {
159 | leftAndRightViewTextField.rightView = makeCalendarButtonView()
160 | uiTextField.rightView = makeCalendarButtonView()
161 | } else {
162 | leftAndRightViewTextField.rightView = nil
163 | uiTextField.rightView = nil
164 | }
165 | }
166 |
167 | private func setLeftViewMode(at index: Int) {
168 |
169 | let mode: UITextField.ViewMode = [.always, .whileEditing, .unlessEditing][index]
170 | leftAndRightViewTextField.leftViewMode = mode
171 | uiTextField.leftViewMode = mode
172 | }
173 |
174 | private func setRightViewMode(at index: Int) {
175 |
176 | let mode: UITextField.ViewMode = [.always, .whileEditing, .unlessEditing][index]
177 | leftAndRightViewTextField.rightViewMode = mode
178 | uiTextField.rightViewMode = mode
179 | }
180 |
181 | @IBAction private func onLeftViewModeChanged(_ control: UISegmentedControl) {
182 |
183 | setLeftViewMode(at: control.selectedSegmentIndex)
184 | }
185 |
186 | @IBAction private func onLeftViewToggled(_ control: UISwitch) {
187 |
188 | setLeftView(visible: control.isOn)
189 | }
190 |
191 | @IBAction private func onRightViewModeChanged(_ control: UISegmentedControl) {
192 |
193 | setRightViewMode(at: control.selectedSegmentIndex)
194 | }
195 |
196 | @IBAction private func onRightViewToggled(_ control: UISwitch) {
197 |
198 | setRightView(visible: control.isOn)
199 | }
200 |
201 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
202 |
203 | textField.resignFirstResponder()
204 |
205 | return false
206 | }
207 |
208 | private func showNotification(_ message: String) {
209 |
210 | notificationLabel.text = message
211 |
212 | notificationView.alpha = 1.0
213 | let animations: () -> Void = { [view = notificationView] in view?.alpha = 0 }
214 | UIView.animate(withDuration: 0.33, delay: 0.66, options: [], animations: animations)
215 | }
216 | }
217 |
218 |
--------------------------------------------------------------------------------
/Example/RAGTextField/Outline.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/Example/RAGTextField/OutlineViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import RAGTextField
3 |
4 | final class OutlineViewController: UIViewController, UITextFieldDelegate {
5 |
6 | @IBOutlet private weak var outlineTextField: RAGTextField! {
7 | didSet {
8 | outlineTextField.delegate = self
9 |
10 | let bgView = OutlineView(frame: .zero)
11 | bgView.lineWidth = 1
12 | bgView.lineColor = ColorPalette.savanna
13 | bgView.fillColor = nil
14 | bgView.cornerRadius = 6.0
15 | outlineTextField.textColor = ColorPalette.stone
16 | outlineTextField.tintColor = ColorPalette.stone
17 | outlineTextField.textBackgroundView = bgView
18 | outlineTextField.textPadding = UIEdgeInsets(top: 8.0, left: 8.0, bottom: 8.0, right: 8.0)
19 | outlineTextField.textPaddingMode = .text
20 | outlineTextField.scaledPlaceholderOffset = 0.0
21 | outlineTextField.placeholderMode = .scalesWhenEditing
22 | outlineTextField.placeholderScaleWhenEditing = 0.8
23 | outlineTextField.placeholderColor = ColorPalette.savanna
24 | }
25 | }
26 |
27 | @IBOutlet private weak var outlineAndFillTextField: RAGTextField! {
28 | didSet {
29 | outlineAndFillTextField.delegate = self
30 |
31 | let bgView = OutlineView(frame: .zero)
32 | bgView.lineWidth = 2
33 | bgView.lineColor = ColorPalette.stone
34 | bgView.fillColor = ColorPalette.midnight
35 | bgView.cornerRadius = 4.0
36 |
37 | outlineAndFillTextField.textColor = ColorPalette.star
38 | outlineAndFillTextField.tintColor = ColorPalette.star
39 | outlineAndFillTextField.textBackgroundView = bgView
40 | outlineAndFillTextField.textPadding = UIEdgeInsets(top: 12.0, left: 8.0, bottom: 12.0, right: 8.0)
41 | outlineAndFillTextField.textPaddingMode = .textAndPlaceholder
42 | outlineAndFillTextField.scaledPlaceholderOffset = 0.0
43 | outlineAndFillTextField.placeholderMode = .scalesWhenEditing
44 | outlineAndFillTextField.placeholderScaleWhenEditing = 0.8
45 | outlineAndFillTextField.placeholderColor = ColorPalette.stone
46 | outlineAndFillTextField.transformedPlaceholderColor = outlineAndFillTextField.tintColor
47 | outlineAndFillTextField.hintColor = ColorPalette.stone
48 | outlineAndFillTextField.hintOffset = 2.0
49 | outlineAndFillTextField.hintFont = UIFont.systemFont(ofSize: 11.0)
50 | outlineAndFillTextField.hint = "Enter some text"
51 | }
52 | }
53 |
54 | @IBOutlet private weak var boxTextField: RAGTextField! {
55 | didSet {
56 | boxTextField.delegate = self
57 |
58 | let bgView = OutlineView(frame: .zero)
59 | bgView.lineWidth = 1.0 / UIScreen.main.scale // 1 pixel
60 | bgView.lineColor = ColorPalette.sky
61 | bgView.fillColor = ColorPalette.chalk
62 | bgView.cornerRadius = 0.0
63 | boxTextField.textBackgroundView = bgView
64 | boxTextField.textPadding = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 16.0, right: 16.0)
65 | boxTextField.textPaddingMode = .textAndPlaceholderAndHint
66 | boxTextField.scaledPlaceholderOffset = 0.0
67 | boxTextField.placeholderMode = .scalesWhenEditing
68 | boxTextField.placeholderScaleWhenEditing = 0.8
69 | boxTextField.placeholderColor = ColorPalette.sky
70 | boxTextField.textColor = ColorPalette.midnight
71 | boxTextField.tintColor = ColorPalette.midnight
72 | boxTextField.hintColor = ColorPalette.meadow
73 | boxTextField.hintOffset = 0.0
74 | boxTextField.hintFont = UIFont.systemFont(ofSize: 11.0)
75 | boxTextField.hint = "Enter some text"
76 | }
77 | }
78 |
79 | override func viewDidLoad() {
80 |
81 | title = "Outline"
82 |
83 | super.viewDidLoad()
84 | }
85 |
86 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
87 |
88 | textField.resignFirstResponder()
89 |
90 | return false
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/Example/RAGTextField/Placeholder.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/Example/RAGTextField/PlaceholderViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import RAGTextField
3 |
4 | final class PlaceholderViewController: UIViewController, UITextFieldDelegate {
5 |
6 | @IBOutlet private weak var simpleTextField: RAGTextField! {
7 | didSet {
8 | simpleTextField.placeholderMode = .simple
9 | setUp(simpleTextField)
10 | }
11 | }
12 |
13 | @IBOutlet private weak var whenNotEmptyTextField: RAGTextField! {
14 | didSet {
15 | whenNotEmptyTextField.placeholderMode = .scalesWhenNotEmpty
16 | setUp(whenNotEmptyTextField)
17 | }
18 | }
19 |
20 | @IBOutlet private weak var whenEditingTextField: RAGTextField! {
21 | didSet {
22 | whenEditingTextField.placeholderMode = .scalesWhenEditing
23 | setUp(whenEditingTextField)
24 | }
25 | }
26 |
27 | @IBOutlet private weak var offsetTextField: RAGTextField! {
28 | didSet {
29 | offsetTextField.placeholderMode = .scalesWhenEditing
30 | setUp(offsetTextField, color: ColorPalette.savanna.withAlphaComponent(0.1))
31 | }
32 | }
33 |
34 | @IBOutlet weak var placeholderOffsetControl: UISegmentedControl! {
35 | didSet {
36 | placeholderOffsetControl.tintColor = ColorPalette.savanna
37 | }
38 | }
39 |
40 | private func setUp(_ textField: RAGTextField, color: UIColor = ColorPalette.chalk) {
41 |
42 | textField.delegate = self
43 | textField.textColor = ColorPalette.midnight
44 | textField.tintColor = ColorPalette.midnight
45 | textField.textBackgroundView = makeTextBackgroundView(color: color)
46 | textField.textPadding = UIEdgeInsets(top: 4.0, left: 4.0, bottom: 4.0, right: 4.0)
47 | textField.textPaddingMode = .textAndPlaceholderAndHint
48 | textField.scaledPlaceholderOffset = 2.0
49 | textField.placeholderScaleWhenEditing = 0.8
50 | textField.placeholderColor = ColorPalette.stone
51 | }
52 |
53 | private func makeTextBackgroundView(color: UIColor) -> UIView {
54 |
55 | let view = UIView()
56 | view.layer.cornerRadius = 4.0
57 | view.backgroundColor = color
58 |
59 | return view
60 | }
61 |
62 | override func viewDidLoad() {
63 |
64 | title = "Placeholder"
65 |
66 | setPlaceholderOffset(at: placeholderOffsetControl.selectedSegmentIndex)
67 |
68 | super.viewDidLoad()
69 | }
70 |
71 | @IBAction func onPlaceholderOffsetChanged(_ control: UISegmentedControl) {
72 |
73 | setPlaceholderOffset(at: control.selectedSegmentIndex)
74 | }
75 |
76 | private func setPlaceholderOffset(at index: Int) {
77 |
78 | _ = offsetTextField.resignFirstResponder()
79 |
80 | let offset: CGFloat = [0.0, 8.0, 16.0][index]
81 | offsetTextField.scaledPlaceholderOffset = offset
82 |
83 | let value = "Offset by \(Int(offset))pt"
84 | offsetTextField.text = value
85 | }
86 |
87 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
88 |
89 | textField.resignFirstResponder()
90 |
91 | return false
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Example/RAGTextField/TextAlignment.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/Example/RAGTextField/TextAlignmentViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import RAGTextField
3 |
4 | final class TextAlignmentViewController: UIViewController, UITextFieldDelegate {
5 |
6 | @IBOutlet private weak var naturalAlignmentTextField: RAGTextField! {
7 | didSet {
8 | setUp(naturalAlignmentTextField)
9 | naturalAlignmentTextField.hintColor = .darkGray
10 | naturalAlignmentTextField.hintFont = UIFont.systemFont(ofSize: 11.0)
11 | naturalAlignmentTextField.hint = "Based on user interface direction"
12 | }
13 | }
14 |
15 | @IBOutlet private weak var differentAlignmentsTextField: RAGTextField! {
16 | didSet {
17 | setUp(differentAlignmentsTextField)
18 | differentAlignmentsTextField.hintColor = ColorPalette.meadow
19 | differentAlignmentsTextField.hintFont = UIFont.systemFont(ofSize: 11.0)
20 | }
21 | }
22 |
23 | @IBOutlet private weak var textAlignmentControl: UISegmentedControl! {
24 | didSet {
25 | textAlignmentControl.tintColor = ColorPalette.meadow
26 | }
27 | }
28 |
29 | private func setUp(_ textField: RAGTextField) {
30 |
31 | textField.delegate = self
32 | textField.clearButtonMode = .whileEditing
33 | textField.textColor = ColorPalette.midnight
34 | textField.tintColor = ColorPalette.midnight
35 | textField.textBackgroundView = makeTextBackgroundView()
36 | textField.textPadding = UIEdgeInsets(top: 4.0, left: 4.0, bottom: 4.0, right: 4.0)
37 | textField.textPaddingMode = .textAndPlaceholderAndHint
38 | textField.scaledPlaceholderOffset = 2.0
39 | textField.placeholderMode = .scalesWhenEditing
40 | textField.placeholderScaleWhenEditing = 0.8
41 | textField.placeholderColor = ColorPalette.stone
42 | }
43 |
44 | private func makeTextBackgroundView() -> UIView {
45 |
46 | let view = UIView()
47 | view.layer.cornerRadius = 4.0
48 | view.backgroundColor = ColorPalette.chalk
49 |
50 | return view
51 | }
52 |
53 | override func viewDidLoad() {
54 |
55 | title = "Text alignment"
56 |
57 | super.viewDidLoad()
58 |
59 | setTextAlignement(at: textAlignmentControl.selectedSegmentIndex)
60 | }
61 |
62 | @IBAction func onTextAlignmentChanged(_ control: UISegmentedControl) {
63 |
64 | setTextAlignement(at: control.selectedSegmentIndex)
65 | }
66 |
67 | private func setTextAlignement(at index: Int) {
68 |
69 | _ = differentAlignmentsTextField.resignFirstResponder()
70 |
71 | let alignment: NSTextAlignment = [.left, .center, .right][index]
72 | differentAlignmentsTextField.textAlignment = alignment
73 | differentAlignmentsTextField.hint = hint(for: alignment)
74 | }
75 |
76 | private func hint(for textAlignment: NSTextAlignment) -> String {
77 |
78 | switch textAlignment {
79 | case .left:
80 | return "Left alignment"
81 | case .center:
82 | return "Center alignment"
83 | case .right:
84 | return "Right alignment"
85 | case .natural:
86 | return "Natural alignment"
87 | case .justified:
88 | return "Justified alignment"
89 | @unknown default:
90 | return "Unknown alignment"
91 | }
92 | }
93 |
94 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
95 |
96 | textField.resignFirstResponder()
97 |
98 | return false
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/Example/RAGTextField/TextPadding.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/Example/RAGTextField/TextPaddingViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import RAGTextField
3 |
4 | final class TextPaddingViewController: UIViewController, UITextFieldDelegate {
5 |
6 | @IBOutlet private weak var defaultTextField: RAGTextField! {
7 | didSet {
8 | setUp(defaultTextField, color: ColorPalette.chalk)
9 | defaultTextField.textPadding = UIEdgeInsets(top: 4.0, left: 4.0, bottom: 4.0, right: 4.0)
10 | }
11 | }
12 |
13 | @IBOutlet private weak var paddedTextField: RAGTextField! {
14 | didSet {
15 | setUp(paddedTextField, color: ColorPalette.bramble.withAlphaComponent(0.2))
16 | paddedTextField.placeholderColor = ColorPalette.midnight.withAlphaComponent(0.66)
17 | paddedTextField.hintColor = ColorPalette.midnight
18 | paddedTextField.hintFont = UIFont.systemFont(ofSize: 11.0)
19 | paddedTextField.textColor = ColorPalette.bramble
20 | paddedTextField.tintColor = ColorPalette.stone
21 | paddedTextField.text = "Text"
22 | }
23 | }
24 |
25 | @IBOutlet private weak var paddingControl: UISegmentedControl! {
26 | didSet {
27 | paddingControl.tintColor = ColorPalette.bramble
28 | }
29 | }
30 |
31 | @IBOutlet private weak var includePlaceholderSwitch: UISwitch! {
32 | didSet {
33 | includePlaceholderSwitch.tintColor = ColorPalette.bramble
34 | includePlaceholderSwitch.onTintColor = ColorPalette.bramble
35 | }
36 | }
37 |
38 | @IBOutlet private weak var includeHintSwitch: UISwitch! {
39 | didSet {
40 | includeHintSwitch.tintColor = ColorPalette.bramble
41 | includeHintSwitch.onTintColor = ColorPalette.bramble
42 | }
43 | }
44 |
45 | private func setUp(_ textField: RAGTextField, color: UIColor) {
46 |
47 | textField.delegate = self
48 | textField.textColor = ColorPalette.midnight
49 | textField.tintColor = ColorPalette.midnight
50 | textField.textBackgroundView = makeTextBackgroundView(color: color)
51 | textField.textPaddingMode = .textAndPlaceholderAndHint
52 | textField.hintOffset = 2.0
53 | textField.scaledPlaceholderOffset = 2.0
54 | textField.placeholderMode = .scalesWhenEditing
55 | textField.placeholderScaleWhenEditing = 0.8
56 | textField.placeholderColor = ColorPalette.stone
57 | }
58 |
59 | private func makeTextBackgroundView(color: UIColor) -> UIView {
60 |
61 | let view = UIView()
62 | view.layer.cornerRadius = 4.0
63 | view.backgroundColor = color
64 |
65 | return view
66 | }
67 |
68 | override func viewDidLoad() {
69 |
70 | title = "Text padding"
71 |
72 | super.viewDidLoad()
73 |
74 | setPadding(at: paddingControl.selectedSegmentIndex)
75 | updateTextPaddingMode()
76 | }
77 |
78 | private func setPadding(at index: Int) {
79 |
80 | _ = paddedTextField.resignFirstResponder()
81 |
82 | let padding: CGFloat = [4.0, 8.0, 16.0][index]
83 | paddedTextField.textPadding = UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding)
84 | }
85 |
86 | private func updateTextPaddingMode() {
87 |
88 | let mode: RAGTextPaddingMode
89 | switch (includePlaceholderSwitch.isOn, includeHintSwitch.isOn) {
90 | case (true, true):
91 | mode = .textAndPlaceholderAndHint
92 | case (true, _):
93 | mode = .textAndPlaceholder
94 | case (_, true):
95 | mode = .textAndHint
96 | default:
97 | mode = .text
98 | }
99 |
100 | paddedTextField.textPaddingMode = mode
101 | paddedTextField.hint = hint(for: mode)
102 | }
103 |
104 | @IBAction private func onIncludePlaceholderChanged(_ control: UISwitch) {
105 |
106 | updateTextPaddingMode()
107 | }
108 |
109 | @IBAction private func onIncludeHintChanged(_ control: UISwitch) {
110 |
111 | updateTextPaddingMode()
112 | }
113 |
114 | private func hint(for mode: RAGTextPaddingMode) -> String {
115 |
116 | switch mode {
117 | case .text:
118 | return "Text mode"
119 | case .textAndHint:
120 | return "Text + hint mode"
121 | case .textAndPlaceholder:
122 | return "Text + placeholder mode"
123 | case .textAndPlaceholderAndHint:
124 | return "Text + placeholder + hint mode"
125 | }
126 | }
127 |
128 | @IBAction private func onPaddingChanged(_ control: UISegmentedControl) {
129 |
130 | setPadding(at: control.selectedSegmentIndex)
131 | }
132 |
133 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
134 |
135 | textField.resignFirstResponder()
136 |
137 | return false
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/Example/RAGTextField/UIColor+Hex.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension UIColor {
4 |
5 | /// Creates a color from the given hex value.
6 | ///
7 | /// - parameter hex: A 6-digit hex value, e.g. 0xff0000.
8 | ///
9 | /// - returns: The color corresponding to the given hex value
10 | convenience init(hex: Int) {
11 | let r = CGFloat((hex >> 16) & 0xff) / 255.0
12 | let g = CGFloat((hex >> 8) & 0xff) / 255.0
13 | let b = CGFloat((hex >> 0) & 0xff) / 255.0
14 |
15 | self.init(red: r, green: g, blue: b, alpha: 1.0)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Example/RAGTextField/Underline.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/Example/RAGTextField/UnderlineViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import RAGTextField
3 |
4 | final class UnderlineViewController: UIViewController, UITextFieldDelegate {
5 |
6 | @IBOutlet private weak var underlineTextField: RAGTextField! {
7 | didSet {
8 | underlineTextField.delegate = self
9 |
10 | let bgView = UnderlineView(frame: .zero)
11 | bgView.textField = underlineTextField
12 | bgView.backgroundLineColor = ColorPalette.midnight
13 | bgView.foregroundLineColor = ColorPalette.flame
14 | bgView.foregroundLineWidth = 2.0
15 | bgView.expandDuration = 0.2
16 | bgView.backgroundColor = ColorPalette.chalk
17 | if #available(iOS 11, *) {
18 | bgView.layer.cornerRadius = 4.0
19 | bgView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
20 | }
21 |
22 | underlineTextField.tintColor = ColorPalette.flame
23 | underlineTextField.textBackgroundView = bgView
24 | underlineTextField.textPadding = UIEdgeInsets(top: 8.0, left: 8.0, bottom: 8.0, right: 8.0)
25 | underlineTextField.textPaddingMode = .textAndPlaceholderAndHint
26 | underlineTextField.scaledPlaceholderOffset = 0.0
27 | underlineTextField.placeholderMode = .scalesWhenEditing
28 | underlineTextField.placeholderScaleWhenEditing = 0.8
29 | underlineTextField.placeholderColor = ColorPalette.midnight.withAlphaComponent(0.66)
30 | underlineTextField.transformedPlaceholderColor = underlineTextField.tintColor
31 | underlineTextField.hint = nil
32 | }
33 | }
34 |
35 | @IBOutlet private weak var underlineModeTextField: RAGTextField! {
36 | didSet {
37 | underlineModeTextField.delegate = self
38 |
39 | let bgView = UnderlineView(frame: .zero)
40 | bgView.textField = underlineModeTextField
41 | bgView.backgroundLineColor = ColorPalette.midnight
42 | bgView.foregroundLineColor = ColorPalette.midnight
43 | bgView.foregroundLineWidth = 3.0
44 | bgView.expandDuration = 0.2
45 | bgView.backgroundColor = ColorPalette.sky
46 | if #available(iOS 11, *) {
47 | bgView.layer.cornerRadius = 8.0
48 | bgView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
49 | }
50 |
51 | underlineModeTextField.textColor = .white
52 | underlineModeTextField.tintColor = .white
53 | underlineModeTextField.textBackgroundView = bgView
54 | underlineModeTextField.textPadding = UIEdgeInsets(top: 12.0, left: 12.0, bottom: 12.0, right: 12.0)
55 | underlineModeTextField.textPaddingMode = .textAndPlaceholder
56 | underlineModeTextField.scaledPlaceholderOffset = 0.0
57 | underlineModeTextField.placeholderMode = .scalesWhenEditing
58 | underlineModeTextField.placeholderScaleWhenEditing = 0.66
59 | underlineModeTextField.placeholderColor = .white
60 | underlineModeTextField.hintFont = UIFont.systemFont(ofSize: 11.0)
61 | underlineModeTextField.hintColor = ColorPalette.sky
62 | underlineModeTextField.hintOffset = 3.0
63 | underlineModeTextField.hint = "Natural mode supported as well"
64 | }
65 | }
66 |
67 | @IBOutlet private weak var boxTextField: RAGTextField! {
68 | didSet {
69 | boxTextField.delegate = self
70 |
71 | let bgView = UnderlineView(frame: .zero)
72 | bgView.textField = boxTextField
73 | bgView.backgroundLineColor = ColorPalette.stone
74 | bgView.foregroundLineColor = ColorPalette.bramble
75 | bgView.foregroundLineWidth = 2.0
76 | bgView.expandDuration = 0.2
77 | bgView.expandMode = .expandsInUserInterfaceDirection
78 | bgView.backgroundColor = ColorPalette.chalk
79 |
80 | boxTextField.textColor = ColorPalette.bramble
81 | boxTextField.tintColor = ColorPalette.bramble
82 | boxTextField.textBackgroundView = bgView
83 | boxTextField.textPadding = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 8.0, right: 16.0)
84 | boxTextField.textPaddingMode = .textAndPlaceholderAndHint
85 | boxTextField.scaledPlaceholderOffset = 0.0
86 | boxTextField.placeholderMode = .scalesWhenEditing
87 | boxTextField.placeholderScaleWhenEditing = 0.8
88 | boxTextField.placeholderColor = ColorPalette.midnight.withAlphaComponent(0.66)
89 | boxTextField.transformedPlaceholderColor = boxTextField.tintColor
90 | boxTextField.hintFont = UIFont.systemFont(ofSize: 11.0)
91 | boxTextField.hintColor = ColorPalette.midnight
92 | boxTextField.hintOffset = 0.0
93 | boxTextField.hint = "Enter some text"
94 | }
95 | }
96 |
97 | @IBOutlet private weak var underlineModeControl: UISegmentedControl! {
98 | didSet {
99 | underlineModeControl.tintColor = ColorPalette.sky
100 | }
101 | }
102 |
103 | override func viewDidLoad() {
104 |
105 | title = "Underline"
106 |
107 | setUnderlineMode(at: underlineModeControl.selectedSegmentIndex)
108 |
109 | super.viewDidLoad()
110 | }
111 |
112 | private func setUnderlineMode(at index: Int) {
113 |
114 | let mode: UnderlineView.Mode = [.expandsFromLeft, .expandsFromCenter, .expandsFromRight, .notAnimated][index]
115 | (underlineModeTextField.textBackgroundView as? UnderlineView)?.expandMode = mode
116 | }
117 |
118 | @IBAction private func onUnderlineModeChanged(_ control: UISegmentedControl) {
119 |
120 | setUnderlineMode(at: control.selectedSegmentIndex)
121 | }
122 |
123 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
124 |
125 | textField.resignFirstResponder()
126 |
127 | return false
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/Example/RAGTextField/ViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
4 |
5 | private enum Topic: String {
6 |
7 | case placeholder
8 | case hint
9 | case textAlignment
10 | case textPadding
11 | case outline
12 | case underline
13 | case leftAndRightViews
14 |
15 | static var allTopics: [Topic] {
16 | return [
17 | .placeholder,
18 | .hint,
19 | .textAlignment,
20 | .textPadding,
21 | .outline,
22 | .underline,
23 | .leftAndRightViews
24 | ]
25 | }
26 | }
27 |
28 | override func viewDidLoad() {
29 |
30 | title = "Overview"
31 |
32 | if #available(iOS 11, *) {
33 | navigationController?.navigationBar.prefersLargeTitles = true
34 | }
35 |
36 | super.viewDidLoad()
37 | }
38 |
39 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
40 |
41 | return Topic.allTopics.count
42 | }
43 |
44 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
45 |
46 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
47 | cell.textLabel?.text = title(for: Topic.allTopics[indexPath.row])
48 | cell.textLabel?.textColor = .darkGray
49 | cell.accessoryType = .disclosureIndicator
50 |
51 | return cell
52 | }
53 |
54 | private func title(for topic: Topic) -> String {
55 |
56 | switch topic {
57 | case .placeholder:
58 | return "Animated placeholder"
59 | case .hint:
60 | return "Hint label"
61 | case .textAlignment:
62 | return "Text alignments"
63 | case .textPadding:
64 | return "Text padding"
65 | case .outline:
66 | return "Outlined style"
67 | case .underline:
68 | return "Underlined style"
69 | case .leftAndRightViews:
70 | return "Left and right views"
71 | }
72 | }
73 |
74 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
75 |
76 | tableView.deselectRow(at: indexPath, animated: true)
77 |
78 | let topic = Topic.allTopics[indexPath.row]
79 |
80 | let storyboardName = formatStoryboardName(for: topic)
81 | guard Bundle.main.path(forResource: storyboardName, ofType: "storyboardc") != nil else {
82 | return
83 | }
84 |
85 | let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
86 | if let viewController = storyboard.instantiateInitialViewController() {
87 | navigationController?.pushViewController(viewController, animated: true)
88 | }
89 | }
90 |
91 | func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
92 |
93 | return CGFloat.leastNonzeroMagnitude
94 | }
95 |
96 | private func formatStoryboardName(for topic: Topic) -> String {
97 |
98 | let value = topic.rawValue
99 | let name = value.prefix(1).uppercased() + value.dropFirst()
100 |
101 | return name
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Example/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/Tests/Tests.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import XCTest
3 | import RAGTextField
4 |
5 | class Tests: XCTestCase {
6 |
7 | override func setUp() {
8 | super.setUp()
9 | // Put setup code here. This method is called before the invocation of each test method in the class.
10 | }
11 |
12 | override func tearDown() {
13 | // Put teardown code here. This method is called after the invocation of each test method in the class.
14 | super.tearDown()
15 | }
16 |
17 | func testExample() {
18 | // This is an example of a functional test case.
19 | XCTAssert(true, "Pass")
20 | }
21 |
22 | func testPerformanceExample() {
23 | // This is an example of a performance test case.
24 | self.measure() {
25 | // Put the code you want to measure the time of here.
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 raginmari
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "RAGTextField",
6 | platforms: [
7 | .iOS(.v9)
8 | ],
9 | products: [
10 | .library(name: "RAGTextField", targets: ["RAGTextField"])
11 | ],
12 | targets: [
13 | .target(name: "RAGTextField")
14 | ]
15 | )
16 |
--------------------------------------------------------------------------------
/RAGTextField.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'RAGTextField'
3 | s.version = '0.14.0'
4 | s.summary = 'Subclass of UITextField featuring a floating placeholder and a hint label.'
5 | s.description = 'Subclass of UITextField that adds an animated placeholder and an optional hint label below the text. Supports an arbitrary view in the background of the text (outline and underline views are provided) as well as the left and right views, text alignments, flexible padding and offsets.'
6 | s.homepage = 'https://github.com/raginmari/RAGTextField'
7 | s.license = { :type => 'MIT', :file => 'LICENSE' }
8 | s.author = { 'raginmari' => 'reimar.twelker@web.de' }
9 | s.source = { :git => 'https://github.com/raginmari/RAGTextField.git', :tag => s.version.to_s }
10 | s.ios.deployment_target = '9.0'
11 | s.swift_version = '5.0'
12 | s.source_files = 'Sources/RAGTextField/Classes/**/*'
13 | end
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RAGTextField
2 |
3 | [](https://appcenter.ms/users/raginmari/apps/RAGTextField-Demo-App/build/branches)
4 | [](http://cocoapods.org/pods/RAGTextField)
5 | [](http://cocoapods.org/pods/RAGTextField)
6 | [](http://cocoapods.org/pods/RAGTextField)
7 | [](https://github.com/Carthage/Carthage)
8 |
9 | Subclass of `UITextField` that adds an animated placeholder and an optional hint label below the text.
10 |
11 | It supports an arbitrary view in the background of the text (outline and underline views are provided) as well as the left and right views, text alignments, flexible padding and offsets.
12 |
13 | ## Example
14 |
15 | To run the example project, clone the repo, and run `pod install` from the Example directory first.
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | ## Requirements
25 |
26 | Written in Swift 5. Requires iOS 9.
27 |
28 | Swift support:
29 |
30 | | Swift version | Library version |
31 | |---------------|-----------------|
32 | | 3 | <= 0.2.1 |
33 | | 4 | <= 0.12.1 |
34 | | 5 | from 0.13.0 |
35 |
36 | ## Installation
37 |
38 | `RAGTextField` is available through [Swift Package Manager](https://swift.org/package-manager) (SPM), [CocoaPods](http://cocoapods.org) and [Carthage](https://github.com/Carthage/Carthage).
39 |
40 | #### Cocoapods
41 |
42 | Add the following line to your Podfile:
43 |
44 | ```ruby
45 | pod "RAGTextField"
46 | ```
47 |
48 | Please try the pod by calling `pod try RAGTextField` in the terminal.
49 |
50 | #### Carthage
51 |
52 | Add the following line to your Cartfile:
53 |
54 | ```ruby
55 | github "raginmari/RAGTextField"
56 | ```
57 |
58 | ## How to use
59 |
60 | After installing the lib and importing the module `RAGTextField`, the text field can be used like any other text field (both in the code and in your storyboards and nibs).
61 |
62 | These are the key differences to `UITextField`:
63 | - A **floating placeholder** inspired by the one described in Google's [Material Design](https://material.io/guidelines/components/text-fields.html#text-fields-labels) guidelines.
64 | - A **hint label** below the actual text which can be used to provide additional hints or report errors.
65 | - A view in the **background of the text** (excluding the placeholder and the hint label) which can be used to style the appearance of the text entry. The example project uses this capability.
66 |
67 | Many properties of the text field are `IBInspectable`.
68 |
69 | #### The placeholder
70 |
71 | The placeholder replaces the superclass placeholder. Values assigned to the `placeholder` property are handled exclusively by `RAGTextField`. The text alignment of the placeholder matches the text alignment of the text field.
72 |
73 | These are the different ways you can **customize the appearance** and behavior of the placeholder:
74 |
75 | - Use the `placeholderFont` property to assign a **custom font or font size** to the placeholder. By default, the placeholder uses the font of the text field.
76 | - Use the `placeholderColor` property to **change the color** of the placeholder. By default, the placeholder uses the text color of the text field.
77 | - Use the `transformedPlaceholderColor` property to set a color that is applied to the placeholder when the text field is being edited and the placeholder is transformed to its floating position.
78 | - Use the `placeholderScaleWhenEditing` property to specify the **scale applied to the placeholder** in its floating position above the text. The default value is 1.
79 | - Use the `scaledPlaceholderOffset` property to offset the placeholder in its floating position from the text. The default value is 0. Positive values **move the placeholder up**, away from the text.
80 | - The value of the `placeholderMode` property determines the **behavior of the placeholder**:
81 | - `scalesWhenEditing` (default): the placeholder is transformed as soon as the text field becomes the first responder. Moreover, the placeholder remains transformed as long as there is text in the text field.
82 | - `scalesWhenNotEmpty`: the placeholder is transformed as soon as and for as long as there is text in the text field.
83 | - `scalesAlways`: the placeholder is always displayed in the transformed position.
84 | - `simple`: the floating placeholder is disabled. The behavior of the placeholder resembles that of the superclass.
85 | - Use the `placeholderAnimationDuration` property to adjust the **duration of the animation of the placeholder** when it moves to or from the floating position. If the value is `nil`, a default value is used. Set the value to 0 to **disable** the placeholder animation.
86 |
87 | #### The hint label
88 |
89 | The hint label is disabled by default and while the value of the `hint` property is `nil`. If a non-nil value is assigned to the `hint` property (including the empty string), the layout of the label is updated and space for the hint label is reserved. The text alignment of the hint matches the text alignment of the text field. The hint supports multiple lines of text.
90 |
91 | These are the different ways you can **customize the appearance** of the hint:
92 |
93 | - Use the `hintFont` property to assign a **custom font or font size** to the hint. By default, the hint uses the font of the text field.
94 | - Use the `hintColor` property to **change the color** of the hint. By default, the hint uses the text color of the text field.
95 | - Use the `hintOffset` property to offset the hint label from the text. The default value is 0. Positive values **move the hint down**, away from the text.
96 | - Use the `layoutAlwaysIncludesHint` property to always keep the hint label in the layout even if the `hint`value is `nil`. The default value of this property is `false`.
97 |
98 | #### The text background view
99 |
100 | Add a view to the background of the text by assigning an arbitrary view to the `textBackgroundView` property. Its frame is updated by `RAGTextField` when required. The view is sized so that it matches the size of the text (and placeholder and/or hint) plus padding.
101 |
102 | These are the different ways you can **customize the appearance** of the text background view.
103 |
104 | - Use the `textPadding` property to apply padding to the text. The padding expands the text background view. By default, the padding is `.zero`.
105 | - Use the `textPaddingMode` property to apply the text padding to just the text or in addition to that to the placeholder, the hint or both. Can be used to wrap the respective subviews into the text background view. The example project uses the text padding mode.
106 |
107 | #### The underline view
108 |
109 | Use the class `UnderlineView` to draw an **animated underline** below the text. Assign an instance of the class to the `textBackgroundView` property of the text field. The appearance of the underline can either be updated automatically by the view itself (see its `textField` property) or be manually controlled from a view controller or text field delegate. The example project uses the underline view.
110 |
111 | #### The outline view
112 | Use the class `OutlineView` to draw an outline around the text. The outline can have rounded corners and it can be filled and inset. Assign an instance of the class to the `textBackgroundView` property of the text field. Depending on the `textPaddingMode` value, the outline optionally includes the placeholder and/or hint label.
113 |
114 | ## Bond
115 | If you want to use the text field with the fantastic [Bond](https://github.com/DeclarativeHub/Bond), you can add these extensions so that you can bind to the `hint` and `placeholder` properties:
116 |
117 | ```swift
118 | extension ReactiveExtensions where Base: RAGTextField {
119 |
120 | var hint: Bond {
121 | return bond { textField, hint in
122 | textField.hint = hint
123 | }
124 | }
125 |
126 | var placeholder: Bond {
127 | return bond { textField, placeholder in
128 | textField.placeholder = placeholder
129 | }
130 | }
131 | }
132 | ```
133 |
134 | ## Known issues
135 |
136 | These are known or possible issues with `RAGTextField`:
137 |
138 | - The `attributedText` property of UITextField *may* not be supported.
139 | - The `attributedPlaceholder` of UITextField is not supported.
140 | - The `borderStyle` property should be `.none`.
141 |
142 | These issues will hopefully be addressed in future updates.
143 |
144 | ## Author
145 |
146 | raginmari, reimar.twelker@web.de
147 |
148 | ## License
149 |
150 | RAGTextField is available under the MIT license. See the LICENSE file for more info.
151 |
--------------------------------------------------------------------------------
/Sources/RAGTextField/Assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raginmari/RAGTextField/9a4b1237aed03e365931887d18b7398bc477df26/Sources/RAGTextField/Assets/.gitkeep
--------------------------------------------------------------------------------
/Sources/RAGTextField/Classes/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raginmari/RAGTextField/9a4b1237aed03e365931887d18b7398bc477df26/Sources/RAGTextField/Classes/.gitkeep
--------------------------------------------------------------------------------
/Sources/RAGTextField/Classes/Extensions/String+RAGTextField.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2017 Reimar Twelker
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | extension String {
26 |
27 | func size(using font: UIFont, availableWidth: CGFloat = .greatestFiniteMagnitude) -> CGSize {
28 |
29 | let size = CGSize(width: availableWidth, height: .greatestFiniteMagnitude)
30 | let options: NSStringDrawingOptions = [ .usesLineFragmentOrigin, .usesFontLeading ]
31 | let boundingRect = self.boundingRect(with: size, options: options, attributes: [ .font: font ], context: nil)
32 | let ceilSize = CGSize(width: ceil(boundingRect.width), height: ceil(boundingRect.height))
33 |
34 | return ceilSize
35 | }
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/Sources/RAGTextField/Classes/PlaceholderView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2017 Reimar Twelker
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | private enum Constants {
26 |
27 | static let scaleAnimationKey = "scale"
28 | }
29 |
30 | /// Used to animate and transform a placeholder label using Core Animation in a view hierarchy that otherwise uses Auto Layout.
31 | final class PlaceholderView: UIView {
32 |
33 | override init(frame: CGRect) {
34 |
35 | super.init(frame: frame)
36 | commonInit()
37 | }
38 |
39 | required init?(coder: NSCoder) {
40 |
41 | super.init(coder: coder)
42 | commonInit()
43 | }
44 |
45 | private func commonInit() {
46 |
47 | isUserInteractionEnabled = false
48 | }
49 |
50 | /// The embedded label.
51 | ///
52 | /// Its layout does not use Auto Layout so that Core Animation can be used to transform the label.
53 | private(set) lazy var label: UILabel = {
54 |
55 | let label = UILabel()
56 | label.textColor = UIColor(white: 0.75, alpha: 1.0)
57 | addSubview(label)
58 |
59 | return label
60 | }()
61 |
62 | /// Updates the text alignment property of the label.
63 | ///
64 | /// - Warning
65 | /// Must be used instead of setting the property of the label directly.
66 | var textAlignment: NSTextAlignment {
67 | get {
68 | return label.textAlignment
69 | }
70 | set {
71 | label.textAlignment = newValue
72 | updateAnchorPoint(of: label, textAlignment: newValue)
73 | }
74 | }
75 |
76 | private func updateAnchorPoint(of view: UIView, textAlignment: NSTextAlignment) {
77 |
78 | switch (textAlignment, UIApplication.shared.userInterfaceLayoutDirection) {
79 | case (.natural, .leftToRight), (.justified, .leftToRight), (.left, _):
80 | view.layer.anchorPoint = CGPoint(x: 0.0, y: 0.5)
81 | case (.natural, .rightToLeft), (.justified, .rightToLeft), (.right, _):
82 | view.layer.anchorPoint = CGPoint(x: 1.0, y: 0.5)
83 | case (.center, _):
84 | view.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
85 | @unknown default:
86 | // Use left-to-right value
87 | view.layer.anchorPoint = CGPoint(x: 0.0, y: 0.5)
88 | }
89 |
90 | view.frame = bounds
91 | }
92 |
93 | func scaleLabel(to scale: CGFloat, animated: Bool, duration: TimeInterval) {
94 |
95 | layoutIfNeeded()
96 | label.layer.removeAllAnimations()
97 |
98 | let transform = CATransform3DMakeScale(scale, scale, 1.0)
99 |
100 | if animated {
101 | let animation = CABasicAnimation(keyPath: "transform")
102 | let currentTransform = label.layer.presentation()?.transform ?? label.layer.transform
103 | animation.fromValue = currentTransform
104 | animation.toValue = transform
105 | animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
106 | animation.duration = duration
107 | label.layer.add(animation, forKey: Constants.scaleAnimationKey)
108 | }
109 |
110 | label.layer.transform = transform
111 | }
112 |
113 | override var intrinsicContentSize: CGSize {
114 |
115 | let infinite = CGFloat.greatestFiniteMagnitude
116 | let size = label.systemLayoutSizeFitting(CGSize(width: infinite, height: infinite))
117 |
118 | return size
119 | }
120 |
121 | override func layoutSubviews() {
122 |
123 | super.layoutSubviews()
124 |
125 | if !isAnimating() {
126 | label.frame = bounds
127 | }
128 | }
129 |
130 | private func isAnimating() -> Bool {
131 |
132 | return label.layer.animation(forKey: Constants.scaleAnimationKey) != nil
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/Sources/RAGTextField/Classes/RAGTextFieldPlaceholderMode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2017 Reimar Twelker
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import Foundation
24 |
25 | /// The different modes of the placeholder
26 | public enum RAGTextFieldPlaceholderMode {
27 |
28 | /// The default behavior of `UITextField`
29 | case simple
30 |
31 | /// The placeholder scales when it is not empty and when the text field is being edited
32 | case scalesWhenEditing
33 |
34 | /// The placeholder scales when it is not empty
35 | case scalesWhenNotEmpty
36 |
37 | /// The placeholder is locked in the transformed position above the text field
38 | case scalesAlways
39 |
40 | var scalesPlaceholder: Bool {
41 | switch self {
42 | case .simple:
43 | return false
44 | case .scalesWhenEditing:
45 | return true
46 | case .scalesWhenNotEmpty:
47 | return true
48 | case .scalesAlways:
49 | return true
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Sources/RAGTextField/Classes/RAGTextPaddingMode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2017 Reimar Twelker
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import Foundation
24 |
25 | /// The different ways the text padding is applied to the subviews of the text field.
26 | public enum RAGTextPaddingMode {
27 |
28 | /// Text padding is applied to the text.
29 | case text
30 |
31 | /// Text padding is applied to the text and the placeholder.
32 | case textAndPlaceholder
33 |
34 | /// Text padding is applied to the text, the placeholder and the hint.
35 | case textAndPlaceholderAndHint
36 |
37 | /// Text padding is applied to the text and the hint.
38 | case textAndHint
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/RAGTextField/Classes/Views/OutlineView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Reimar Twelker
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | /// Draws an outline along its bounds.
26 | ///
27 | /// The outline can be inset and its corners can be rounded. The inside of the outline can be filled.
28 | open class OutlineView: UIView {
29 |
30 | /// Uses a shape layer instead of the default one.
31 | override open class var layerClass : AnyClass {
32 |
33 | return CAShapeLayer.self
34 | }
35 |
36 | /// Convenience method force casts the layer to `CAShapeLayer`.
37 | private var shapeLayer: CAShapeLayer {
38 |
39 | return layer as! CAShapeLayer
40 | }
41 |
42 | /// The padding around the outline.
43 | open var outlineInsets: UIEdgeInsets = .zero {
44 | didSet {
45 | setNeedsLayout()
46 | }
47 | }
48 |
49 | /// The width of the outline in points.
50 | @IBInspectable open var lineWidth: CGFloat = 1.0 {
51 | didSet {
52 | shapeLayer.lineWidth = lineWidth
53 | }
54 | }
55 |
56 | /// The color of the outline.
57 | @IBInspectable open var lineColor: UIColor? = .black {
58 | didSet {
59 | shapeLayer.strokeColor = lineColor?.cgColor
60 | }
61 | }
62 |
63 | /// The color of the inside of the outline.
64 | @IBInspectable open var fillColor: UIColor? = .clear {
65 | didSet {
66 | shapeLayer.fillColor = fillColor?.cgColor
67 | }
68 | }
69 |
70 | /// The corner radius of the outline.
71 | @IBInspectable open var cornerRadius: CGFloat = 0.0 {
72 | didSet {
73 | shapeLayer.cornerRadius = cornerRadius
74 | setNeedsLayout()
75 | }
76 | }
77 |
78 | public override init(frame: CGRect) {
79 |
80 | super.init(frame: frame)
81 | commonInit()
82 | }
83 |
84 | public required init?(coder aDecoder: NSCoder) {
85 |
86 | super.init(coder: aDecoder)
87 | commonInit()
88 | }
89 |
90 | private func commonInit() {
91 |
92 | backgroundColor = .clear
93 | shapeLayer.fillColor = nil
94 | }
95 |
96 | open override func layoutSubviews() {
97 |
98 | super.layoutSubviews()
99 |
100 | shapeLayer.path = makePath().cgPath
101 | }
102 |
103 | /// Creates the path of the outline.
104 | ///
105 | /// - Returns: The new path.
106 | private func makePath() -> UIBezierPath {
107 |
108 | let rect: CGRect
109 | if outlineInsets != .zero {
110 | rect = bounds.inset(by: outlineInsets)
111 | } else {
112 | rect = bounds
113 | }
114 |
115 | let path: UIBezierPath
116 | if cornerRadius != 0.0 {
117 | path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
118 | } else {
119 | path = UIBezierPath(rect: rect)
120 | }
121 |
122 | return path
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/Sources/RAGTextField/Classes/Views/UnderlineView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Reimar Twelker
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | /// Draws two colored lines at the bottom on top of one another that extend from the left to the right edge.
26 | ///
27 | /// The foreground line is initially not visible. It can be expanded to fully cover the background line.
28 | /// The expansion can be animated in different ways.
29 | ///
30 | /// - Note
31 | /// The view is meant to be used with `RAGTextField`. Set it as the `textBackgroundView` to approximate the look and feel of a
32 | /// Material text field. The expansion of the line has to be controlled manually, for example from the text field delegate.
33 | open class UnderlineView: UIView {
34 |
35 | /// The different ways in which the expanding line is animated.
36 | public enum Mode {
37 |
38 | /// The line equally expands from the center of the view to its left and right edges.
39 | case expandsFromCenter
40 |
41 | /// The line expands from the right edge of the view to the left.
42 | case expandsFromRight
43 |
44 | /// The line expands from the left edge of the view to the right.
45 | case expandsFromLeft
46 |
47 | /// The line expands from the leading edge of the view to the trailing one.
48 | case expandsInUserInterfaceDirection
49 |
50 | /// The line is not animated.
51 | case notAnimated
52 | }
53 |
54 | /// The width of both the foreground line in points.
55 | @IBInspectable open var foregroundLineWidth: CGFloat = 1.0 {
56 | didSet {
57 | heightConstraint?.constant = foregroundLineWidth
58 | }
59 | }
60 |
61 | /// The color of the background line.
62 | @IBInspectable open var backgroundLineColor: UIColor = .clear {
63 | didSet {
64 | underlineBackgroundView.backgroundColor = backgroundLineColor
65 | }
66 | }
67 |
68 | /// The color of the foreground line.
69 | @IBInspectable open var foregroundLineColor: UIColor = .black {
70 | didSet {
71 | underlineView.backgroundColor = foregroundLineColor
72 | }
73 | }
74 |
75 | /// The way the foreground line is expanded.
76 | open var expandMode: Mode = .expandsFromCenter {
77 | didSet {
78 | setNeedsUpdateConstraints()
79 | }
80 | }
81 |
82 | /// The duration of the animation of the foreground line.
83 | open var expandDuration: TimeInterval = 0.2
84 |
85 | private let underlineView = UIView()
86 | private let underlineBackgroundView = UIView()
87 |
88 | /// Used to pin the foreground line to the leading edge of the view.
89 | ///
90 | /// Enabled and disabled depending on the `expandMode` value.
91 | private var leadingConstraint: NSLayoutConstraint?
92 |
93 | /// Used to pin the foreground line to the trailing edge of the view.
94 | ///
95 | /// Enabled and disabled depending on the `expandMode` value.
96 | private var trailingConstraint: NSLayoutConstraint?
97 |
98 | /// Used to animate the foreground line.
99 | private var widthConstraint: NSLayoutConstraint?
100 |
101 | /// Updated when `lineWidth` is changed.
102 | private var heightConstraint: NSLayoutConstraint?
103 |
104 | /// If `true`, the foreground line is currently expanded.
105 | private var isExpanded = false
106 |
107 | /// Whether the underline is animated when the associated text field begins editing.
108 | ///
109 | /// If `false`, the underline is updated but not animated. The default value is `true`.
110 | ///
111 | /// - Note
112 | /// For this property to take effect, the `textField` property must be set.
113 | open var animatesWhenEditingBegins = true
114 |
115 | /// Whether the underline is animated when the associated text field ends editing.
116 | ///
117 | /// If `false`, the underline is updated but not animated. The default value is `true`.
118 | ///
119 | /// - Note
120 | /// For this property to take effect, the `textField` property must be set.
121 | open var animatesWhenEditingEnds = true
122 |
123 | /// Refers to the text field whose editing state is used to update the appearance of the underline automatically.
124 | ///
125 | /// If `nil`, the appearance of the underline must be updated manually, for example from a view controller or text field delegate.
126 | open weak var textField: UITextField? {
127 | didSet {
128 | if let oldTextField = oldValue {
129 | stopObserving(oldTextField)
130 | }
131 |
132 | if let newTextField = textField {
133 | startObserving(newTextField)
134 | }
135 | }
136 | }
137 |
138 | /// The tint color of the `UIView` overwrites the current `expandedLineColor`.
139 | open override var tintColor: UIColor! {
140 | didSet {
141 | foregroundLineColor = tintColor
142 | }
143 | }
144 |
145 | public override init(frame: CGRect) {
146 | super.init(frame: frame)
147 | commonInit()
148 | }
149 |
150 | public required init?(coder aDecoder: NSCoder) {
151 | super.init(coder: aDecoder)
152 | commonInit()
153 | }
154 |
155 | private func commonInit() {
156 |
157 | addSubview(underlineBackgroundView)
158 | addSubview(underlineView)
159 | setUpUnderlineBackground()
160 | setUpUnderline()
161 | }
162 |
163 | /// Sets up the underline background view. Sets properties and configures constraints.
164 | private func setUpUnderlineBackground() {
165 |
166 | underlineBackgroundView.backgroundColor = backgroundLineColor
167 | underlineBackgroundView.translatesAutoresizingMaskIntoConstraints = false
168 |
169 | let views = ["v": underlineBackgroundView]
170 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v]|", options: [], metrics: nil, views: views))
171 |
172 | // Cling to the bottom of the view
173 | underlineBackgroundView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
174 |
175 | // Always be as high as the underline
176 | let onePixel = 1.0 / UIScreen.main.scale
177 | underlineBackgroundView.heightAnchor.constraint(equalToConstant: onePixel).isActive = true
178 | }
179 |
180 | /// Sets up the underline view. Sets properties and configures constraints.
181 | private func setUpUnderline() {
182 |
183 | underlineView.backgroundColor = foregroundLineColor
184 | underlineView.translatesAutoresizingMaskIntoConstraints = false
185 |
186 | // Cling to the bottom of the view
187 | underlineView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
188 |
189 | heightConstraint = underlineView.heightAnchor.constraint(equalToConstant: foregroundLineWidth)
190 | heightConstraint?.isActive = true
191 |
192 | // (De)activating the higher priority width constraint animates the underline
193 | widthConstraint = underlineView.widthAnchor.constraint(equalTo: widthAnchor)
194 | widthConstraint?.priority = .defaultHigh
195 |
196 | let zeroWidthConstraint = underlineView.widthAnchor.constraint(equalToConstant: 0.0)
197 | zeroWidthConstraint.priority = .defaultHigh - 1
198 | zeroWidthConstraint.isActive = true
199 |
200 | leadingConstraint = underlineView.leadingAnchor.constraint(equalTo: leadingAnchor)
201 | // Do not activate just yet
202 |
203 | trailingConstraint = underlineView.trailingAnchor.constraint(equalTo: trailingAnchor)
204 | // Do not activate just yet
205 |
206 | // Center with low priority
207 | let centerConstraint = underlineView.centerXAnchor.constraint(equalTo: centerXAnchor)
208 | centerConstraint.priority = .defaultLow
209 | centerConstraint.isActive = true
210 |
211 | setNeedsUpdateConstraints()
212 | }
213 |
214 | private func stopObserving(_ textField: UITextField) {
215 |
216 | NotificationCenter.default.removeObserver(self, name: UITextField.textDidBeginEditingNotification, object: textField)
217 | NotificationCenter.default.removeObserver(self, name: UITextField.textDidEndEditingNotification, object: textField)
218 | }
219 |
220 | private func startObserving(_ textField: UITextField) {
221 |
222 | NotificationCenter.default.addObserver(self,
223 | selector: #selector(onDidBeginEditing(_:)),
224 | name: UITextField.textDidBeginEditingNotification,
225 | object: textField)
226 | NotificationCenter.default.addObserver(self,
227 | selector: #selector(onDidEndEditing(_:)),
228 | name: UITextField.textDidEndEditingNotification,
229 | object: textField)
230 | }
231 |
232 | @objc private func onDidBeginEditing(_ notification: Notification) {
233 |
234 | setExpanded(true, animated: animatesWhenEditingBegins)
235 | }
236 |
237 | @objc private func onDidEndEditing(_ notification: Notification) {
238 |
239 | setExpanded(false, animated: animatesWhenEditingEnds)
240 | }
241 |
242 | open override func updateConstraints() {
243 |
244 | // Enable the leading and trailing constraints depending on the `expandMode`.
245 | switch expandMode {
246 | case .expandsFromCenter, .notAnimated:
247 | leadingConstraint?.isActive = false
248 | trailingConstraint?.isActive = false
249 | case .expandsFromRight where UIApplication.shared.userInterfaceLayoutDirection == .leftToRight:
250 | leadingConstraint?.isActive = false
251 | trailingConstraint?.isActive = true
252 | case .expandsFromRight:
253 | leadingConstraint?.isActive = true
254 | trailingConstraint?.isActive = false
255 | case .expandsFromLeft where UIApplication.shared.userInterfaceLayoutDirection == .leftToRight:
256 | leadingConstraint?.isActive = true
257 | trailingConstraint?.isActive = false
258 | case .expandsFromLeft:
259 | leadingConstraint?.isActive = false
260 | trailingConstraint?.isActive = true
261 | case .expandsInUserInterfaceDirection:
262 | leadingConstraint?.isActive = true
263 | trailingConstraint?.isActive = false
264 | }
265 |
266 | super.updateConstraints()
267 | }
268 |
269 | /// Sets the foreground line to its expanded or contracted state depending on the given parameter. Optionally, the change is animated.
270 | ///
271 | /// - Parameters:
272 | /// - expanded: If `true`, the line is expanded.
273 | /// - animated: If `true`, the change is animated.
274 | open func setExpanded(_ expanded: Bool, animated: Bool) {
275 |
276 | guard expanded != isExpanded else {
277 | return
278 | }
279 |
280 | widthConstraint?.isActive = expanded
281 |
282 | if animated && expandMode != .notAnimated {
283 | UIView.animate(withDuration: expandDuration) { [unowned self] in
284 | self.layoutIfNeeded()
285 | }
286 | }
287 |
288 | isExpanded = expanded
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/_Pods.xcodeproj:
--------------------------------------------------------------------------------
1 | Example/Pods/Pods.xcodeproj
--------------------------------------------------------------------------------