├── .swift-version ├── Screenshots ├── Isao.gif ├── Jiro.gif ├── Yoko.gif ├── Akira.gif ├── Hoshi.gif ├── Kaede.gif ├── Madoka.gif ├── Minoru.gif └── Yoshiko.gif ├── .swiftpm └── xcode │ └── package 2.xcworkspace │ └── contents.xcworkspacedata ├── TextFieldEffects ├── TextFieldEffects.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── TextFieldEffects.xcscheme │ └── project.pbxproj ├── TextFieldEffects │ ├── TextFieldEffects.h │ ├── Info.plist │ ├── TextFieldEffects.swift │ ├── AkiraTextField.swift │ ├── KaedeTextField.swift │ ├── MinoruTextField.swift │ ├── JiroTextField.swift │ ├── IsaoTextField.swift │ ├── MadokaTextField.swift │ ├── HoshiTextField.swift │ ├── YoshikoTextField.swift │ └── YokoTextField.swift └── TextFieldsDemo │ ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── ExampleTableViewController.swift │ ├── Info.plist │ ├── AppDelegate.swift │ └── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── .travis.yml ├── Package.swift ├── .gitignore ├── .github └── stale.yml ├── LICENSE ├── CHANGELOG.md ├── README.md └── TextFieldEffects.podspec /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 2 | -------------------------------------------------------------------------------- /Screenshots/Isao.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raulriera/TextFieldEffects/HEAD/Screenshots/Isao.gif -------------------------------------------------------------------------------- /Screenshots/Jiro.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raulriera/TextFieldEffects/HEAD/Screenshots/Jiro.gif -------------------------------------------------------------------------------- /Screenshots/Yoko.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raulriera/TextFieldEffects/HEAD/Screenshots/Yoko.gif -------------------------------------------------------------------------------- /Screenshots/Akira.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raulriera/TextFieldEffects/HEAD/Screenshots/Akira.gif -------------------------------------------------------------------------------- /Screenshots/Hoshi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raulriera/TextFieldEffects/HEAD/Screenshots/Hoshi.gif -------------------------------------------------------------------------------- /Screenshots/Kaede.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raulriera/TextFieldEffects/HEAD/Screenshots/Kaede.gif -------------------------------------------------------------------------------- /Screenshots/Madoka.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raulriera/TextFieldEffects/HEAD/Screenshots/Madoka.gif -------------------------------------------------------------------------------- /Screenshots/Minoru.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raulriera/TextFieldEffects/HEAD/Screenshots/Minoru.gif -------------------------------------------------------------------------------- /Screenshots/Yoshiko.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raulriera/TextFieldEffects/HEAD/Screenshots/Yoshiko.gif -------------------------------------------------------------------------------- /.swiftpm/xcode/package 2.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: swift 2 | osx_image: xcode10 3 | xcode_project: TextFieldEffects/TextFieldEffects.xcodeproj 4 | xcode_schema: TextFieldEffects 5 | notifications: 6 | disabled: true 7 | script: 8 | - xcodebuild -scheme TextFieldEffects -destination "OS=12.0,name=iPhone SE" -sdk iphonesimulator12.0 | xcpretty -c 9 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.2 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "TextFieldEffects", 8 | products: [ 9 | .library(name: "TextFieldEffects", targets: ["TextFieldEffects"]), 10 | ], 11 | targets: [ 12 | .target(name: "TextFieldEffects", path: "TextFieldEffects/TextFieldEffects") 13 | ] 14 | ) 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | .DS_Store 28 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/TextFieldEffects.h: -------------------------------------------------------------------------------- 1 | // 2 | // TextFieldEffects.h 3 | // TextFieldEffects 4 | // 5 | // Created by Raúl Riera on 05/03/2015. 6 | // Copyright (c) 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for TextFieldEffects. 12 | FOUNDATION_EXPORT double TextFieldEffectsVersionNumber; 13 | 14 | //! Project version string for TextFieldEffects. 15 | FOUNDATION_EXPORT const unsigned char TextFieldEffectsVersionString[]; 16 | 17 | // In this header, you should import all the open headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 21 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 3 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | # Label to use when marking an issue as stale 9 | staleLabel: stale 10 | # Comment to post when marking an issue as stale. Set to `false` to disable 11 | markComment: > 12 | This issue has been automatically marked as stale because it has not had 13 | recent activity. It will be closed in 3 days if no further activity occurs. 14 | # Comment to post when closing a stale issue. Set to `false` to disable 15 | closeComment: false 16 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldsDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldsDemo/ExampleTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleTableViewController.swift 3 | // TextFieldEffects 4 | // 5 | // Created by Raúl Riera on 28/08/2015. 6 | // Copyright © 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import TextFieldEffects 11 | 12 | class ExampleTableViewController : UITableViewController { 13 | 14 | @IBOutlet private var textFields: [TextFieldEffects]! 15 | 16 | /** 17 | Set this value to true if you want to see all the "firstName" 18 | textFields prepopulated with the name "Raul" (for testing purposes) 19 | */ 20 | let prefillTextFields = false 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | 25 | guard prefillTextFields == true else { return } 26 | 27 | _ = textFields.map { $0.text = "Raul" } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/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 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Raul Riera 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Version 1.6.0 4 | * Support for Swift 5 and Xcode 11 5 | 6 | ## Version 1.5.1 7 | * Syntax improvements 8 | * Removed old Swift 4.2 migration code 9 | 10 | ## Version 1.5.0 11 | * Support for iOS 12 12 | 13 | ## Version 1.4.0 14 | * Support for iOS 11 15 | 16 | ## Version 1.3.3 17 | * Fixes https://github.com/raulriera/TextFieldEffects/issues/118 18 | 19 | ## Version 1.3.2 20 | * Renaming broke the project 21 | * Fixes https://github.com/raulriera/TextFieldEffects/issues/120 22 | 23 | ## Version 1.3.1 24 | * Fixes https://github.com/raulriera/TextFieldEffects/issues/67 25 | * Remove all project's warnings 26 | 27 | ## Version 1.3.0 28 | * Swift 3.0 support 29 | 30 | ## Version 1.2.0 31 | * Swift 2.2 support 32 | * Support for animation completion blocks 33 | 34 | ## Version 1.1.1 35 | * Fixes bug #57 in Yoshiko 36 | 37 | ## Version 1.1.0 38 | * Support to change the placeholder font via the `placeholderFontScale` property. 39 | * Fixed some minor issues with the example project. 40 | 41 | ## Version 1.0.0 42 | * Initial release with 9 different UITextField effects. 43 | * Full Interface Builder support. 44 | * Full code only support. 45 | * Cocoapods support. 46 | * Carthage support. 47 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldsDemo/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 | UIInterfaceOrientationLandscapeRight 38 | UIInterfaceOrientationPortraitUpsideDown 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldsDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // TextFieldsDemo 4 | // 5 | // Created by Raúl Riera on 22/01/2015. 6 | // Copyright (c) 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | @nonobjc func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TextFieldEffects [![Build Status](https://travis-ci.org/raulriera/TextFieldEffects.svg?branch=master)](https://travis-ci.org/raulriera/TextFieldEffects) 2 | 3 | I fell in love with the text inputs effects in [this article](http://tympanus.net/codrops/2015/01/08/inspiration-text-input-effects/). As an exercise I decided to recreate as many of them as I can using Swift *(some of them have a personal touch)*. 4 | 5 | Currently it features the following effects from the article: 6 | 7 | - [x] Kaede 8 | - [x] Hoshi 9 | - [x] Jiro 10 | - [x] Isao 11 | - [x] Minoru 12 | - [x] Yoko 13 | - [x] Madoka 14 | - [x] Akira 15 | - [x] Yoshiko 16 | 17 | ## How they look 18 | 19 | ### Kaede 20 | 21 | 22 | ### Hoshi 23 | 24 | 25 | ### Jiro 26 | 27 | 28 | ### Isao 29 | 30 | 31 | ### Minoru 32 | 33 | 34 | ### Yoko 35 | 36 | 37 | ### Madoka 38 | 39 | 40 | ### Akira 41 | 42 | 43 | ### Yoshiko 44 | 45 | 46 | ## Installation 47 | 48 | - Looking for Swift 2.3 support? Check out the [1.2.0](https://github.com/raulriera/TextFieldEffects/releases/tag/1.2.0) tag. 49 | - Looking for Swift 2.1 support? Check out the [1.1.1](https://github.com/raulriera/TextFieldEffects/releases/tag/1.1.1) tag. 50 | - Looking for Swift 1.2 support? Check out the `swift-1.2` branch. 51 | 52 | ### Manual 53 | 54 | The easiest way to install this framework is to drag and drop the `TextFieldEffects/TextFieldEffects` folder into your project. This also prevents the `frameworks` [problem in iOS](http://www.openradar.me/21258097) where the IBInspectable and IBDesignable are stripped out. 55 | 56 | ### CocoaPods 57 | 58 | Add the following to your Podfile: 59 | 60 | ``` ruby 61 | use_frameworks! 62 | pod 'TextFieldEffects' 63 | ``` 64 | 65 | ### Carthage 66 | 67 | Add the following to your Cartfile: 68 | 69 | ``` ruby 70 | github 'raulriera/TextFieldEffects' 71 | ``` 72 | 73 | ## How to use them 74 | 75 | Every effect is properly documented in the source code, this is the best way to both understand and see what they do. There is also an example project included with all the effects and their settings. 76 | 77 | ### Interface Builder 78 | 79 | The library is a simple drop-in, as soon as you set your subclass to one of the effects and your module to `TextFieldEffects` you will be able to see all the IBDesignable settings in the storyboard. 80 | 81 | ### Code 82 | 83 | If you like to get your hands dirty, you can use them just like you would normally use any `UITextField` 84 | 85 | ``` swift 86 | let textField = KaedeTextField(frame: textFieldFrame) 87 | textField.placeholderColor = .darkGrayColor() 88 | textField.foregroundColor = .lightGrayColor() 89 | 90 | view.addSubView(textField) 91 | ``` 92 | 93 | Is that simple. 94 | 95 | ## Created by 96 | Raul Riera, [@raulriera](http://twitter.com/raulriera) 97 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldsDemo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /TextFieldEffects.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint TextFieldEffects.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "TextFieldEffects" 19 | s.version = "1.7.0" 20 | s.summary = "Custom drop in UITextFields effects." 21 | 22 | s.description = <<-DESC 23 | TextFieldEffects enables a collection of drop in effects to standard UITextFields. 24 | DESC 25 | 26 | s.homepage = "http://github.com/raulriera/TextFieldEffects" 27 | s.screenshots = "https://raw.githubusercontent.com/raulriera/TextFieldEffects/master/Screenshots/Kaede.gif", "https://raw.githubusercontent.com/raulriera/TextFieldEffects/master/Screenshots/Hoshi.gif", "https://raw.githubusercontent.com/raulriera/TextFieldEffects/master/Screenshots/Jiro.gif", "https://raw.githubusercontent.com/raulriera/TextFieldEffects/master/Screenshots/Isao.gif", "https://raw.githubusercontent.com/raulriera/TextFieldEffects/master/Screenshots/Minoru.gif", "https://raw.githubusercontent.com/raulriera/TextFieldEffects/master/Screenshots/Yoko.gif", "https://raw.githubusercontent.com/raulriera/TextFieldEffects/master/Screenshots/Madoka.gif", 28 | "https://raw.githubusercontent.com/raulriera/TextFieldEffects/master/Screenshots/Akira.gif", 29 | "https://raw.githubusercontent.com/raulriera/TextFieldEffects/master/Screenshots/Yoshiko.gif" 30 | 31 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 32 | # 33 | # Licensing your code is important. See http://choosealicense.com for more info. 34 | # CocoaPods will detect a license file if there is a named LICENSE* 35 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 36 | # 37 | 38 | s.license = "MIT" 39 | 40 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 41 | # 42 | # Specify the authors of the library, with email addresses. Email addresses 43 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 44 | # accepts just a name if you'd rather not provide an email address. 45 | # 46 | # Specify a social_media_url where others can refer to, for example a twitter 47 | # profile URL. 48 | # 49 | 50 | s.author = { "Raul Riera" => "rieraraul@gmail.com" } 51 | s.social_media_url = "http://twitter.com/raulriera" 52 | 53 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 54 | # 55 | # If this Pod runs only on iOS or OS X, then specify the platform and 56 | # the deployment target. You can optionally include the target after the platform. 57 | # 58 | 59 | s.platform = :ios, '8.0' 60 | s.swift_version = '5.0' 61 | 62 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 63 | # 64 | # Specify the location from where the source should be retrieved. 65 | # Supports git, hg, bzr, svn and HTTP. 66 | # 67 | 68 | s.source = { :git => "https://github.com/raulriera/TextFieldEffects.git", :tag => s.version.to_s } 69 | 70 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 71 | # 72 | # CocoaPods is smart about how it includes source code. For source files 73 | # giving a folder will include any h, m, mm, c & cpp files. For header 74 | # files it will include any header in the folder. 75 | # Not including the public_header_files will make all headers public. 76 | # 77 | 78 | s.source_files = 'TextFieldEffects/TextFieldEffects/*.swift' 79 | end 80 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects.xcodeproj/xcshareddata/xcschemes/TextFieldEffects.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 67 | 68 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/TextFieldEffects.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextFieldEffects.swift 3 | // TextFieldEffects 4 | // 5 | // Created by Raúl Riera on 24/01/2015. 6 | // Copyright (c) 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension String { 12 | /** 13 | true if self contains characters. 14 | */ 15 | var isNotEmpty: Bool { 16 | return !isEmpty 17 | } 18 | } 19 | 20 | /** 21 | A TextFieldEffects object is a control that displays editable text and contains the boilerplates to setup unique animations for text entry and display. You typically use this class the same way you use UITextField. 22 | */ 23 | open class TextFieldEffects : UITextField { 24 | /** 25 | The type of animation a TextFieldEffect can perform. 26 | 27 | - TextEntry: animation that takes effect when the textfield has focus. 28 | - TextDisplay: animation that takes effect when the textfield loses focus. 29 | */ 30 | public enum AnimationType: Int { 31 | case textEntry 32 | case textDisplay 33 | } 34 | 35 | /** 36 | Closure executed when an animation has been completed. 37 | */ 38 | public typealias AnimationCompletionHandler = (_ type: AnimationType)->() 39 | 40 | /** 41 | UILabel that holds all the placeholder information 42 | */ 43 | public let placeholderLabel = UILabel() 44 | 45 | /** 46 | Creates all the animations that are used to leave the textfield in the "entering text" state. 47 | */ 48 | open func animateViewsForTextEntry() { 49 | fatalError("\(#function) must be overridden") 50 | } 51 | 52 | /** 53 | Creates all the animations that are used to leave the textfield in the "display input text" state. 54 | */ 55 | open func animateViewsForTextDisplay() { 56 | fatalError("\(#function) must be overridden") 57 | } 58 | 59 | /** 60 | The animation completion handler is the best place to be notified when the text field animation has ended. 61 | */ 62 | open var animationCompletionHandler: AnimationCompletionHandler? 63 | 64 | /** 65 | Draws the receiver’s image within the passed-in rectangle. 66 | 67 | - parameter rect: The portion of the view’s bounds that needs to be updated. 68 | */ 69 | open func drawViewsForRect(_ rect: CGRect) { 70 | fatalError("\(#function) must be overridden") 71 | } 72 | 73 | open func updateViewsForBoundsChange(_ bounds: CGRect) { 74 | fatalError("\(#function) must be overridden") 75 | } 76 | 77 | // MARK: - Overrides 78 | 79 | override open func draw(_ rect: CGRect) { 80 | // FIXME: Short-circuit if the view is currently selected. iOS 11 introduced 81 | // a setNeedsDisplay when you focus on a textfield, calling this method again 82 | // and messing up some of the effects due to the logic contained inside these 83 | // methods. 84 | // This is just a "quick fix", something better needs to come along. 85 | guard isFirstResponder == false else { return } 86 | drawViewsForRect(rect) 87 | } 88 | 89 | override open func drawPlaceholder(in rect: CGRect) { 90 | // Don't draw any placeholders 91 | } 92 | 93 | override open var text: String? { 94 | didSet { 95 | if let text = text, text.isNotEmpty || isFirstResponder { 96 | animateViewsForTextEntry() 97 | } else { 98 | animateViewsForTextDisplay() 99 | } 100 | } 101 | } 102 | 103 | // MARK: - UITextField Observing 104 | 105 | override open func willMove(toSuperview newSuperview: UIView!) { 106 | if newSuperview != nil { 107 | NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidEndEditing), name: UITextField.textDidEndEditingNotification, object: self) 108 | 109 | NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidBeginEditing), name: UITextField.textDidBeginEditingNotification, object: self) 110 | } else { 111 | NotificationCenter.default.removeObserver(self) 112 | } 113 | } 114 | 115 | /** 116 | The textfield has started an editing session. 117 | */ 118 | @objc open func textFieldDidBeginEditing() { 119 | animateViewsForTextEntry() 120 | } 121 | 122 | /** 123 | The textfield has ended an editing session. 124 | */ 125 | @objc open func textFieldDidEndEditing() { 126 | animateViewsForTextDisplay() 127 | } 128 | 129 | // MARK: - Interface Builder 130 | 131 | override open func prepareForInterfaceBuilder() { 132 | drawViewsForRect(frame) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/AkiraTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AkiraTextField.swift 3 | // TextFieldEffects 4 | // 5 | // Created by Mihaela Miches on 5/31/15. 6 | // Copyright (c) 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | An AkiraTextField is a subclass of the TextFieldEffects object, is a control that displays an UITextField with a customizable visual effect around the edges of the control. 13 | */ 14 | @IBDesignable open class AkiraTextField : TextFieldEffects { 15 | private let borderSize: (active: CGFloat, inactive: CGFloat) = (1, 2) 16 | private let borderLayer = CALayer() 17 | private let textFieldInsets = CGPoint(x: 6, y: 0) 18 | private let placeholderInsets = CGPoint(x: 6, y: 0) 19 | 20 | /** 21 | The color of the border. 22 | 23 | This property applies a color to the bounds of the control. The default value for this property is a clear color. 24 | */ 25 | @IBInspectable dynamic open var borderColor: UIColor? { 26 | didSet { 27 | updateBorder() 28 | } 29 | } 30 | 31 | /** 32 | The color of the placeholder text. 33 | 34 | This property applies a color to the complete placeholder string. The default value for this property is a black color. 35 | */ 36 | @IBInspectable dynamic open var placeholderColor: UIColor = .black { 37 | didSet { 38 | updatePlaceholder() 39 | } 40 | } 41 | 42 | /** 43 | The scale of the placeholder font. 44 | 45 | This property determines the size of the placeholder label relative to the font size of the text field. 46 | */ 47 | @IBInspectable dynamic open var placeholderFontScale: CGFloat = 0.7 { 48 | didSet { 49 | updatePlaceholder() 50 | } 51 | } 52 | 53 | override open var placeholder: String? { 54 | didSet { 55 | updatePlaceholder() 56 | } 57 | } 58 | 59 | override open var bounds: CGRect { 60 | didSet { 61 | updateBorder() 62 | } 63 | } 64 | 65 | // MARK: TextFieldEffects 66 | 67 | override open func drawViewsForRect(_ rect: CGRect) { 68 | updateBorder() 69 | updatePlaceholder() 70 | 71 | addSubview(placeholderLabel) 72 | layer.addSublayer(borderLayer) 73 | } 74 | 75 | override open func animateViewsForTextEntry() { 76 | UIView.animate(withDuration: 0.3, animations: { 77 | self.updateBorder() 78 | self.updatePlaceholder() 79 | }, completion: { _ in 80 | self.animationCompletionHandler?(.textEntry) 81 | }) 82 | } 83 | 84 | override open func animateViewsForTextDisplay() { 85 | UIView.animate(withDuration: 0.3, animations: { 86 | self.updateBorder() 87 | self.updatePlaceholder() 88 | }, completion: { _ in 89 | self.animationCompletionHandler?(.textDisplay) 90 | }) 91 | } 92 | 93 | // MARK: Private 94 | 95 | private func updatePlaceholder() { 96 | placeholderLabel.frame = placeholderRect(forBounds: bounds) 97 | placeholderLabel.text = placeholder 98 | placeholderLabel.font = placeholderFontFromFont(font!) 99 | placeholderLabel.textColor = placeholderColor 100 | placeholderLabel.textAlignment = textAlignment 101 | } 102 | 103 | private func updateBorder() { 104 | borderLayer.frame = rectForBounds(bounds) 105 | borderLayer.borderWidth = (isFirstResponder || text!.isNotEmpty) ? borderSize.active : borderSize.inactive 106 | borderLayer.borderColor = borderColor?.cgColor 107 | } 108 | 109 | private func placeholderFontFromFont(_ font: UIFont) -> UIFont! { 110 | let smallerFont = UIFont(descriptor: font.fontDescriptor, size: font.pointSize * placeholderFontScale) 111 | return smallerFont 112 | } 113 | 114 | private var placeholderHeight : CGFloat { 115 | return placeholderInsets.y + placeholderFontFromFont(font!).lineHeight 116 | } 117 | 118 | private func rectForBounds(_ bounds: CGRect) -> CGRect { 119 | return CGRect(x: bounds.origin.x, y: bounds.origin.y + placeholderHeight, width: bounds.size.width, height: bounds.size.height - placeholderHeight) 120 | } 121 | 122 | // MARK: - Overrides 123 | 124 | open override func placeholderRect(forBounds bounds: CGRect) -> CGRect { 125 | if isFirstResponder || text!.isNotEmpty { 126 | return CGRect(x: placeholderInsets.x, y: placeholderInsets.y, width: bounds.width, height: placeholderHeight) 127 | } else { 128 | return textRect(forBounds: bounds) 129 | } 130 | } 131 | 132 | open override func editingRect(forBounds bounds: CGRect) -> CGRect { 133 | return textRect(forBounds: bounds) 134 | } 135 | 136 | override open func textRect(forBounds bounds: CGRect) -> CGRect { 137 | return bounds.offsetBy(dx: textFieldInsets.x, dy: textFieldInsets.y + placeholderHeight/2) 138 | } 139 | } 140 | 141 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/KaedeTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KaedeTextField.swift 3 | // Swish 4 | // 5 | // Created by Raúl Riera on 20/01/2015. 6 | // Copyright (c) 2015 com.raulriera.swishapp. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | A KaedeTextField is a subclass of the TextFieldEffects object, is a control that displays an UITextField with a customizable visual effect around the foreground of the control. 13 | */ 14 | @IBDesignable open class KaedeTextField: TextFieldEffects { 15 | /** 16 | The color of the placeholder text. 17 | 18 | This property applies a color to the complete placeholder string. The default value for this property is a black color. 19 | */ 20 | @IBInspectable dynamic open var placeholderColor: UIColor? { 21 | didSet { 22 | updatePlaceholder() 23 | } 24 | } 25 | 26 | /** 27 | The scale of the placeholder font. 28 | 29 | This property determines the size of the placeholder label relative to the font size of the text field. 30 | */ 31 | @IBInspectable dynamic open var placeholderFontScale: CGFloat = 0.8 { 32 | didSet { 33 | updatePlaceholder() 34 | } 35 | } 36 | 37 | /** 38 | The view’s foreground color. 39 | 40 | The default value for this property is a clear color. 41 | */ 42 | @IBInspectable dynamic open var foregroundColor: UIColor? { 43 | didSet { 44 | updateForegroundColor() 45 | } 46 | } 47 | 48 | /** 49 | The starting x position (as a percentage) of the placeholder area. 50 | */ 51 | @IBInspectable dynamic open var placeholderSplit: CGFloat = 0.6 52 | 53 | override open var placeholder: String? { 54 | didSet { 55 | updatePlaceholder() 56 | } 57 | } 58 | 59 | override open var bounds: CGRect { 60 | didSet { 61 | drawViewsForRect(bounds) 62 | } 63 | } 64 | 65 | private let foregroundView = UIView() 66 | private let placeholderInsets = CGPoint(x: 10, y: 5) 67 | private let textFieldInsets = CGPoint(x: 10, y: 0) 68 | 69 | // MARK: - TextFieldEffects 70 | 71 | override open func drawViewsForRect(_ rect: CGRect) { 72 | let frame = CGRect(origin: .zero, size: CGSize(width: rect.size.width, height: rect.size.height)) 73 | 74 | foregroundView.frame = frame 75 | foregroundView.isUserInteractionEnabled = false 76 | placeholderLabel.frame = frame.insetBy(dx: placeholderInsets.x, dy: placeholderInsets.y) 77 | placeholderLabel.font = placeholderFontFromFont(font!) 78 | 79 | updateForegroundColor() 80 | updatePlaceholder() 81 | 82 | if text!.isNotEmpty || isFirstResponder { 83 | animateViewsForTextEntry() 84 | } 85 | 86 | addSubview(foregroundView) 87 | addSubview(placeholderLabel) 88 | } 89 | 90 | override open func animateViewsForTextEntry() { 91 | let directionOverride: CGFloat 92 | 93 | if #available(iOS 9.0, *) { 94 | directionOverride = UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) == .rightToLeft ? -1.0 : 1.0 95 | } else { 96 | directionOverride = 1.0 97 | } 98 | 99 | UIView.animate(withDuration: 0.35, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 2.0, options: .beginFromCurrentState, animations: ({ 100 | self.placeholderLabel.frame.origin = CGPoint(x: self.frame.size.width * (self.placeholderSplit + 0.05) * directionOverride, y: self.placeholderInsets.y) 101 | }), completion: nil) 102 | 103 | UIView.animate(withDuration: 0.45, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 1.5, options: .beginFromCurrentState, animations: ({ 104 | self.foregroundView.frame.origin = CGPoint(x: self.frame.size.width * self.placeholderSplit * directionOverride, y: 0) 105 | }), completion: { _ in 106 | self.animationCompletionHandler?(.textEntry) 107 | }) 108 | } 109 | 110 | override open func animateViewsForTextDisplay() { 111 | if text!.isEmpty { 112 | UIView.animate(withDuration: 0.3, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 2.0, options: .beginFromCurrentState, animations: ({ 113 | self.placeholderLabel.frame.origin = self.placeholderInsets 114 | }), completion: nil) 115 | 116 | UIView.animate(withDuration: 0.3, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 2.0, options: .beginFromCurrentState, animations: ({ 117 | self.foregroundView.frame.origin = CGPoint.zero 118 | }), completion: { _ in 119 | self.animationCompletionHandler?(.textDisplay) 120 | }) 121 | } 122 | } 123 | 124 | // MARK: - Private 125 | 126 | private func updateForegroundColor() { 127 | foregroundView.backgroundColor = foregroundColor 128 | } 129 | 130 | private func updatePlaceholder() { 131 | placeholderLabel.text = placeholder 132 | placeholderLabel.textColor = placeholderColor 133 | } 134 | 135 | private func placeholderFontFromFont(_ font: UIFont) -> UIFont! { 136 | let smallerFont = UIFont(descriptor: font.fontDescriptor, size: font.pointSize * placeholderFontScale) 137 | return smallerFont 138 | } 139 | 140 | // MARK: - Overrides 141 | 142 | override open func editingRect(forBounds bounds: CGRect) -> CGRect { 143 | var frame = CGRect(origin: bounds.origin, size: CGSize(width: bounds.size.width * placeholderSplit, height: bounds.size.height)) 144 | 145 | if #available(iOS 9.0, *) { 146 | if UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) == .rightToLeft { 147 | frame.origin = CGPoint(x: bounds.size.width - frame.size.width, y: frame.origin.y) 148 | } 149 | } 150 | 151 | return frame.insetBy(dx: textFieldInsets.x, dy: textFieldInsets.y) 152 | } 153 | 154 | override open func textRect(forBounds bounds: CGRect) -> CGRect { 155 | return editingRect(forBounds: bounds) 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/MinoruTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MinoruTextField.swift 3 | // TextFieldEffects 4 | // 5 | // Created by Raúl Riera on 27/01/2015. 6 | // Copyright (c) 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | A MinoruTextField is a subclass of the TextFieldEffects object, is a control that displays an UITextField with a customizable visual effect around the edges of the control. 13 | */ 14 | @IBDesignable open class MinoruTextField: TextFieldEffects { 15 | /** 16 | The color of the placeholder text. 17 | 18 | This property applies a color to the complete placeholder string. The default value for this property is a black color. 19 | */ 20 | @IBInspectable dynamic open var placeholderColor: UIColor = .black { 21 | didSet { 22 | updatePlaceholder() 23 | } 24 | } 25 | 26 | override open var backgroundColor: UIColor? { 27 | set { 28 | backgroundLayerColor = newValue 29 | } 30 | get { 31 | return backgroundLayerColor 32 | } 33 | } 34 | 35 | /** 36 | The scale of the placeholder font. 37 | 38 | This property determines the size of the placeholder label relative to the font size of the text field. 39 | */ 40 | @IBInspectable dynamic open var placeholderFontScale: CGFloat = 0.65 { 41 | didSet { 42 | updatePlaceholder() 43 | } 44 | } 45 | 46 | override open var placeholder: String? { 47 | didSet { 48 | updatePlaceholder() 49 | } 50 | } 51 | 52 | override open var bounds: CGRect { 53 | didSet { 54 | updateBorder() 55 | updatePlaceholder() 56 | } 57 | } 58 | 59 | private let borderThickness: CGFloat = 1 60 | private let placeholderInsets = CGPoint(x: 6, y: 6) 61 | private let textFieldInsets = CGPoint(x: 6, y: 6) 62 | private let borderLayer = CALayer() 63 | private var backgroundLayerColor: UIColor? 64 | 65 | // MARK: - TextFieldEffects 66 | 67 | override open func drawViewsForRect(_ rect: CGRect) { 68 | let frame = CGRect(origin: CGPoint.zero, size: CGSize(width: rect.size.width, height: rect.size.height)) 69 | 70 | placeholderLabel.frame = frame.insetBy(dx: placeholderInsets.x, dy: placeholderInsets.y) 71 | placeholderLabel.font = placeholderFontFromFont(font!) 72 | 73 | updateBorder() 74 | updatePlaceholder() 75 | 76 | layer.insertSublayer(borderLayer, at: 0) 77 | addSubview(placeholderLabel) 78 | } 79 | 80 | override open func animateViewsForTextEntry() { 81 | UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.6, options: .beginFromCurrentState, animations: { 82 | 83 | self.borderLayer.borderColor = self.textColor?.cgColor 84 | self.borderLayer.shadowOffset = CGSize.zero 85 | self.borderLayer.borderWidth = self.borderThickness 86 | self.borderLayer.shadowColor = self.textColor?.cgColor 87 | self.borderLayer.shadowOpacity = 0.5 88 | self.borderLayer.shadowRadius = 1 89 | 90 | }, completion: { _ in 91 | self.animationCompletionHandler?(.textEntry) 92 | }) 93 | } 94 | 95 | override open func animateViewsForTextDisplay() { 96 | if text!.isEmpty { 97 | UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.6, options: .beginFromCurrentState, animations: { 98 | 99 | self.borderLayer.borderColor = nil 100 | self.borderLayer.shadowOffset = CGSize.zero 101 | self.borderLayer.borderWidth = 0 102 | self.borderLayer.shadowColor = nil 103 | self.borderLayer.shadowOpacity = 0 104 | self.borderLayer.shadowRadius = 0 105 | }, completion: { _ in 106 | 107 | self.animationCompletionHandler?(.textDisplay) 108 | }) 109 | 110 | } 111 | } 112 | 113 | // MARK: - Private 114 | 115 | private func updateBorder() { 116 | borderLayer.frame = rectForBorder(frame) 117 | borderLayer.backgroundColor = backgroundColor?.cgColor 118 | } 119 | 120 | private func updatePlaceholder() { 121 | placeholderLabel.text = placeholder 122 | placeholderLabel.textColor = placeholderColor 123 | placeholderLabel.sizeToFit() 124 | layoutPlaceholderInTextRect() 125 | 126 | if isFirstResponder { 127 | animateViewsForTextEntry() 128 | } 129 | } 130 | 131 | private func placeholderFontFromFont(_ font: UIFont) -> UIFont! { 132 | let smallerFont = UIFont(descriptor: font.fontDescriptor, size: font.pointSize * placeholderFontScale) 133 | return smallerFont 134 | } 135 | 136 | private func rectForBorder(_ bounds: CGRect) -> CGRect { 137 | let newRect = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height - font!.lineHeight + textFieldInsets.y) 138 | 139 | return newRect 140 | } 141 | 142 | private func layoutPlaceholderInTextRect() { 143 | 144 | let textRect = self.textRect(forBounds: bounds) 145 | var originX = textRect.origin.x 146 | switch textAlignment { 147 | case .center: 148 | originX += textRect.size.width/2 - placeholderLabel.bounds.width/2 149 | case .right: 150 | originX += textRect.size.width - placeholderLabel.bounds.width 151 | default: 152 | break 153 | } 154 | placeholderLabel.frame = CGRect(x: originX, y: bounds.height - placeholderLabel.frame.height, 155 | width: placeholderLabel.frame.size.width, height: placeholderLabel.frame.size.height) 156 | } 157 | 158 | // MARK: - Overrides 159 | 160 | override open func editingRect(forBounds bounds: CGRect) -> CGRect { 161 | let newBounds = rectForBorder(bounds) 162 | return newBounds.insetBy(dx: textFieldInsets.x, dy: 0) 163 | } 164 | 165 | override open func textRect(forBounds bounds: CGRect) -> CGRect { 166 | let newBounds = rectForBorder(bounds) 167 | 168 | return newBounds.insetBy(dx: textFieldInsets.x, dy: 0) 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/JiroTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JiroTextField.swift 3 | // TextFieldEffects 4 | // 5 | // Created by Raúl Riera on 24/01/2015. 6 | // Copyright (c) 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | A JiroTextField is a subclass of the TextFieldEffects object, is a control that displays an UITextField with a customizable visual effect around the background of the control. 13 | */ 14 | @IBDesignable open class JiroTextField: TextFieldEffects { 15 | /** 16 | The color of the border. 17 | 18 | This property applies a color to the lower edge of the control. The default value for this property is a clear color. 19 | */ 20 | @IBInspectable dynamic open var borderColor: UIColor? { 21 | didSet { 22 | updateBorder() 23 | } 24 | } 25 | 26 | /** 27 | The color of the placeholder text. 28 | 29 | This property applies a color to the complete placeholder string. The default value for this property is a black color. 30 | */ 31 | @IBInspectable dynamic open var placeholderColor: UIColor = .black { 32 | didSet { 33 | updatePlaceholder() 34 | } 35 | } 36 | 37 | /** 38 | The scale of the placeholder font. 39 | 40 | This property determines the size of the placeholder label relative to the font size of the text field. 41 | */ 42 | @IBInspectable dynamic open var placeholderFontScale: CGFloat = 0.65 { 43 | didSet { 44 | updatePlaceholder() 45 | } 46 | } 47 | 48 | override open var placeholder: String? { 49 | didSet { 50 | updatePlaceholder() 51 | } 52 | } 53 | 54 | override open var bounds: CGRect { 55 | didSet { 56 | updateBorder() 57 | updatePlaceholder() 58 | } 59 | } 60 | 61 | private let borderThickness: CGFloat = 2 62 | private let placeholderInsets = CGPoint(x: 8, y: 8) 63 | private let textFieldInsets = CGPoint(x: 8, y: 12) 64 | private let borderLayer = CALayer() 65 | 66 | // MARK: - TextFieldEffects 67 | 68 | override open func drawViewsForRect(_ rect: CGRect) { 69 | let frame = CGRect(origin: CGPoint.zero, size: CGSize(width: rect.size.width, height: rect.size.height)) 70 | 71 | placeholderLabel.frame = frame.insetBy(dx: placeholderInsets.x, dy: placeholderInsets.y) 72 | placeholderLabel.font = placeholderFontFromFont(font!) 73 | 74 | updateBorder() 75 | updatePlaceholder() 76 | 77 | layer.insertSublayer(borderLayer, at: 0) 78 | addSubview(placeholderLabel) 79 | } 80 | 81 | override open func animateViewsForTextEntry() { 82 | borderLayer.frame.origin = CGPoint(x: 0, y: font!.lineHeight) 83 | 84 | UIView.animate(withDuration: 0.2, delay: 0.3, usingSpringWithDamping: 0.8, initialSpringVelocity: 1.0, options: .beginFromCurrentState, animations: ({ 85 | 86 | self.placeholderLabel.frame.origin = CGPoint(x: self.placeholderInsets.x, y: self.borderLayer.frame.origin.y - self.placeholderLabel.bounds.height) 87 | self.borderLayer.frame = self.rectForBorder(self.borderThickness, isFilled: true) 88 | 89 | }), completion: { _ in 90 | self.animationCompletionHandler?(.textEntry) 91 | }) 92 | } 93 | 94 | override open func animateViewsForTextDisplay() { 95 | if text!.isEmpty { 96 | UIView.animate(withDuration: 0.35, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 2.0, options: .beginFromCurrentState, animations: ({ 97 | self.layoutPlaceholderInTextRect() 98 | self.placeholderLabel.alpha = 1 99 | }), completion: { _ in 100 | self.animationCompletionHandler?(.textDisplay) 101 | }) 102 | 103 | borderLayer.frame = rectForBorder(borderThickness, isFilled: false) 104 | } 105 | } 106 | 107 | // MARK: - Private 108 | 109 | private func updateBorder() { 110 | borderLayer.frame = rectForBorder(borderThickness, isFilled: false) 111 | borderLayer.backgroundColor = borderColor?.cgColor 112 | } 113 | 114 | private func updatePlaceholder() { 115 | placeholderLabel.text = placeholder 116 | placeholderLabel.textColor = placeholderColor 117 | placeholderLabel.sizeToFit() 118 | layoutPlaceholderInTextRect() 119 | 120 | if isFirstResponder || text!.isNotEmpty { 121 | animateViewsForTextEntry() 122 | } 123 | } 124 | 125 | private func placeholderFontFromFont(_ font: UIFont) -> UIFont! { 126 | let smallerFont = UIFont(descriptor: font.fontDescriptor, size: font.pointSize * placeholderFontScale) 127 | return smallerFont 128 | } 129 | 130 | private func rectForBorder(_ thickness: CGFloat, isFilled: Bool) -> CGRect { 131 | if isFilled { 132 | return CGRect(origin: CGPoint(x: 0, y: placeholderLabel.frame.origin.y + placeholderLabel.font.lineHeight), size: CGSize(width: frame.width, height: frame.height)) 133 | } else { 134 | return CGRect(origin: CGPoint(x: 0, y: frame.height-thickness), size: CGSize(width: frame.width, height: thickness)) 135 | } 136 | } 137 | 138 | private func layoutPlaceholderInTextRect() { 139 | 140 | if text!.isNotEmpty { 141 | return 142 | } 143 | 144 | let textRect = self.textRect(forBounds: bounds) 145 | var originX = textRect.origin.x 146 | switch self.textAlignment { 147 | case .center: 148 | originX += textRect.size.width/2 - placeholderLabel.bounds.width/2 149 | case .right: 150 | originX += textRect.size.width - placeholderLabel.bounds.width 151 | default: 152 | break 153 | } 154 | placeholderLabel.frame = CGRect(x: originX, y: textRect.size.height/2, 155 | width: placeholderLabel.frame.size.width, height: placeholderLabel.frame.size.height) 156 | } 157 | 158 | // MARK: - Overrides 159 | 160 | override open func editingRect(forBounds bounds: CGRect) -> CGRect { 161 | return bounds.offsetBy(dx: textFieldInsets.x, dy: textFieldInsets.y) 162 | } 163 | 164 | override open func textRect(forBounds bounds: CGRect) -> CGRect { 165 | return bounds.offsetBy(dx: textFieldInsets.x, dy: textFieldInsets.y) 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/IsaoTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IsaoTextField.swift 3 | // TextFieldEffects 4 | // 5 | // Created by Raúl Riera on 29/01/2015. 6 | // Copyright (c) 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | An IsaoTextField is a subclass of the TextFieldEffects object, is a control that displays an UITextField with a customizable visual effect around the lower edge of the control. 13 | */ 14 | @IBDesignable open class IsaoTextField: TextFieldEffects { 15 | /** 16 | The color of the border when it has no content. 17 | 18 | This property applies a color to the lower edge of the control. The default value for this property is a clear color. This value is also applied to the placeholder color. 19 | */ 20 | @IBInspectable dynamic open var inactiveColor: UIColor? { 21 | didSet { 22 | updateBorder() 23 | } 24 | } 25 | 26 | /** 27 | The color of the border when it has content. 28 | 29 | This property applies a color to the lower edge of the control. The default value for this property is a clear color. 30 | */ 31 | @IBInspectable dynamic open var activeColor: UIColor? { 32 | didSet { 33 | updateBorder() 34 | } 35 | } 36 | 37 | /** 38 | The scale of the placeholder font. 39 | 40 | This property determines the size of the placeholder label relative to the font size of the text field. 41 | */ 42 | @IBInspectable dynamic open var placeholderFontScale: CGFloat = 0.7 { 43 | didSet { 44 | updatePlaceholder() 45 | } 46 | } 47 | 48 | override open var placeholder: String? { 49 | didSet { 50 | updatePlaceholder() 51 | } 52 | } 53 | 54 | override open var bounds: CGRect { 55 | didSet { 56 | updateBorder() 57 | updatePlaceholder() 58 | } 59 | } 60 | 61 | private let borderThickness: (active: CGFloat, inactive: CGFloat) = (4, 2) 62 | private let placeholderInsets = CGPoint(x: 6, y: 6) 63 | private let textFieldInsets = CGPoint(x: 6, y: 6) 64 | private let borderLayer = CALayer() 65 | 66 | // MARK: - TextFieldEffects 67 | 68 | override open func drawViewsForRect(_ rect: CGRect) { 69 | let frame = CGRect(origin: .zero, size: CGSize(width: rect.size.width, height: rect.size.height)) 70 | 71 | placeholderLabel.frame = frame.insetBy(dx: placeholderInsets.x, dy: placeholderInsets.y) 72 | placeholderLabel.font = placeholderFontFromFont(font!) 73 | 74 | updateBorder() 75 | updatePlaceholder() 76 | 77 | layer.addSublayer(borderLayer) 78 | addSubview(placeholderLabel) 79 | } 80 | 81 | override open func animateViewsForTextEntry() { 82 | updateBorder() 83 | if let activeColor = activeColor { 84 | performPlaceholderAnimationWithColor(activeColor) 85 | } 86 | } 87 | 88 | override open func animateViewsForTextDisplay() { 89 | updateBorder() 90 | if let inactiveColor = inactiveColor { 91 | performPlaceholderAnimationWithColor(inactiveColor) 92 | } 93 | } 94 | 95 | // MARK: - Private 96 | 97 | private func updateBorder() { 98 | borderLayer.frame = rectForBorder(frame) 99 | borderLayer.backgroundColor = isFirstResponder ? activeColor?.cgColor : inactiveColor?.cgColor 100 | } 101 | 102 | private func updatePlaceholder() { 103 | placeholderLabel.text = placeholder 104 | placeholderLabel.textColor = inactiveColor 105 | placeholderLabel.sizeToFit() 106 | layoutPlaceholderInTextRect() 107 | 108 | if isFirstResponder { 109 | animateViewsForTextEntry() 110 | } 111 | } 112 | 113 | private func placeholderFontFromFont(_ font: UIFont) -> UIFont! { 114 | let smallerFont = UIFont(descriptor: font.fontDescriptor, size: font.pointSize * placeholderFontScale) 115 | return smallerFont 116 | } 117 | 118 | private func rectForBorder(_ bounds: CGRect) -> CGRect { 119 | var newRect:CGRect 120 | 121 | if isFirstResponder { 122 | newRect = CGRect(x: 0, y: bounds.size.height - font!.lineHeight + textFieldInsets.y - borderThickness.active, width: bounds.size.width, height: borderThickness.active) 123 | } else { 124 | newRect = CGRect(x: 0, y: bounds.size.height - font!.lineHeight + textFieldInsets.y - borderThickness.inactive, width: bounds.size.width, height: borderThickness.inactive) 125 | } 126 | 127 | return newRect 128 | } 129 | 130 | private func layoutPlaceholderInTextRect() { 131 | let textRect = self.textRect(forBounds: bounds) 132 | var originX = textRect.origin.x 133 | switch textAlignment { 134 | case .center: 135 | originX += textRect.size.width/2 - placeholderLabel.bounds.width/2 136 | case .right: 137 | originX += textRect.size.width - placeholderLabel.bounds.width 138 | default: 139 | break 140 | } 141 | placeholderLabel.frame = CGRect(x: originX, y: bounds.height - placeholderLabel.frame.height, 142 | width: placeholderLabel.frame.size.width, height: placeholderLabel.frame.size.height) 143 | } 144 | 145 | private func performPlaceholderAnimationWithColor(_ color: UIColor) { 146 | let yOffset: CGFloat = 4 147 | 148 | UIView.animate(withDuration: 0.15, animations: { 149 | self.placeholderLabel.transform = CGAffineTransform(translationX: 0, y: -yOffset) 150 | self.placeholderLabel.alpha = 0 151 | }) { _ in 152 | self.placeholderLabel.transform = .identity 153 | self.placeholderLabel.transform = CGAffineTransform(translationX: 0, y: yOffset) 154 | 155 | UIView.animate(withDuration: 0.15, animations: { 156 | self.placeholderLabel.textColor = color 157 | self.placeholderLabel.transform = .identity 158 | self.placeholderLabel.alpha = 1 159 | }) { _ in 160 | self.animationCompletionHandler?(self.isFirstResponder ? .textEntry : .textDisplay) 161 | } 162 | } 163 | } 164 | 165 | // MARK: - Overrides 166 | 167 | override open func editingRect(forBounds bounds: CGRect) -> CGRect { 168 | let newBounds = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height - font!.lineHeight + textFieldInsets.y) 169 | return newBounds.insetBy(dx: textFieldInsets.x, dy: 0) 170 | } 171 | 172 | override open func textRect(forBounds bounds: CGRect) -> CGRect { 173 | let newBounds = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height - font!.lineHeight + textFieldInsets.y) 174 | 175 | return newBounds.insetBy(dx: textFieldInsets.x, dy: 0) 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/MadokaTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MadokaTextField.swift 3 | // TextFieldEffects 4 | // 5 | // Created by Raúl Riera on 05/02/2015. 6 | // Copyright (c) 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | A MadokaTextField is a subclass of the TextFieldEffects object, is a control that displays an UITextField with a customizable visual effect around the edges of the control. 13 | */ 14 | @IBDesignable open class MadokaTextField: TextFieldEffects { 15 | /** 16 | The color of the placeholder text. 17 | 18 | This property applies a color to the complete placeholder string. The default value for this property is a black color. 19 | */ 20 | @IBInspectable dynamic open var placeholderColor: UIColor = .black { 21 | didSet { 22 | updatePlaceholder() 23 | } 24 | } 25 | 26 | /** 27 | The color of the border. 28 | 29 | This property applies a color to the lower edge of the control. The default value for this property is a clear color. 30 | */ 31 | @IBInspectable dynamic open var borderColor: UIColor? { 32 | didSet { 33 | updateBorder() 34 | } 35 | } 36 | 37 | /** 38 | The scale of the placeholder font. 39 | 40 | This property determines the size of the placeholder label relative to the font size of the text field. 41 | */ 42 | @IBInspectable dynamic open var placeholderFontScale: CGFloat = 0.65 { 43 | didSet { 44 | updatePlaceholder() 45 | } 46 | } 47 | 48 | override open var placeholder: String? { 49 | didSet { 50 | updatePlaceholder() 51 | } 52 | } 53 | 54 | override open var bounds: CGRect { 55 | didSet { 56 | updateBorder() 57 | updatePlaceholder() 58 | } 59 | } 60 | 61 | private let borderThickness: CGFloat = 1 62 | private let placeholderInsets = CGPoint(x: 6, y: 6) 63 | private let textFieldInsets = CGPoint(x: 6, y: 6) 64 | private let borderLayer = CAShapeLayer() 65 | private var backgroundLayerColor: UIColor? 66 | 67 | // MARK: - TextFieldEffects 68 | 69 | override open func drawViewsForRect(_ rect: CGRect) { 70 | let frame = CGRect(origin: CGPoint.zero, size: CGSize(width: rect.size.width, height: rect.size.height)) 71 | 72 | placeholderLabel.frame = frame.insetBy(dx: placeholderInsets.x, dy: placeholderInsets.y) 73 | placeholderLabel.font = placeholderFontFromFont(font!) 74 | 75 | updateBorder() 76 | updatePlaceholder() 77 | 78 | layer.addSublayer(borderLayer) 79 | addSubview(placeholderLabel) 80 | } 81 | 82 | override open func animateViewsForTextEntry() { 83 | borderLayer.strokeEnd = 1 84 | 85 | UIView.animate(withDuration: 0.3, animations: { 86 | let translate = CGAffineTransform(translationX: -self.placeholderInsets.x, y: self.placeholderLabel.bounds.height + (self.placeholderInsets.y * 2)) 87 | let scale = CGAffineTransform(scaleX: 0.9, y: 0.9) 88 | 89 | self.placeholderLabel.transform = translate.concatenating(scale) 90 | }) { _ in 91 | self.animationCompletionHandler?(.textEntry) 92 | } 93 | } 94 | 95 | override open func animateViewsForTextDisplay() { 96 | if text!.isEmpty { 97 | borderLayer.strokeEnd = percentageForBottomBorder() 98 | 99 | UIView.animate(withDuration: 0.3, animations: { 100 | self.placeholderLabel.transform = .identity 101 | }) { _ in 102 | self.animationCompletionHandler?(.textDisplay) 103 | } 104 | } 105 | } 106 | 107 | // MARK: - Private 108 | 109 | private func updateBorder() { 110 | let rect = rectForBorder(bounds) 111 | let path = UIBezierPath() 112 | path.move(to: CGPoint(x: rect.origin.x + borderThickness, y: rect.height - borderThickness)) 113 | path.addLine(to: CGPoint(x: rect.width - borderThickness, y: rect.height - borderThickness)) 114 | path.addLine(to: CGPoint(x: rect.width - borderThickness, y: rect.origin.y + borderThickness)) 115 | path.addLine(to: CGPoint(x: rect.origin.x + borderThickness, y: rect.origin.y + borderThickness)) 116 | path.close() 117 | borderLayer.path = path.cgPath 118 | borderLayer.lineCap = .square 119 | borderLayer.lineWidth = borderThickness 120 | borderLayer.fillColor = nil 121 | borderLayer.strokeColor = borderColor?.cgColor 122 | borderLayer.strokeEnd = percentageForBottomBorder() 123 | } 124 | 125 | private func percentageForBottomBorder() -> CGFloat { 126 | let borderRect = rectForBorder(bounds) 127 | let sumOfSides = (borderRect.width * 2) + (borderRect.height * 2) 128 | return (borderRect.width * 100 / sumOfSides) / 100 129 | } 130 | 131 | private func updatePlaceholder() { 132 | placeholderLabel.text = placeholder 133 | placeholderLabel.textColor = placeholderColor 134 | placeholderLabel.sizeToFit() 135 | layoutPlaceholderInTextRect() 136 | 137 | if isFirstResponder || text!.isNotEmpty { 138 | animateViewsForTextEntry() 139 | } 140 | } 141 | 142 | private func placeholderFontFromFont(_ font: UIFont) -> UIFont! { 143 | let smallerFont = UIFont(descriptor: font.fontDescriptor, size: font.pointSize * placeholderFontScale) 144 | return smallerFont 145 | } 146 | 147 | private func rectForBorder(_ bounds: CGRect) -> CGRect { 148 | let newRect = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height - font!.lineHeight + textFieldInsets.y) 149 | 150 | return newRect 151 | } 152 | 153 | private func layoutPlaceholderInTextRect() { 154 | placeholderLabel.transform = CGAffineTransform.identity 155 | 156 | let textRect = self.textRect(forBounds: bounds) 157 | var originX = textRect.origin.x 158 | switch textAlignment { 159 | case .center: 160 | originX += textRect.size.width/2 - placeholderLabel.bounds.width/2 161 | case .right: 162 | originX += textRect.size.width - placeholderLabel.bounds.width 163 | default: 164 | break 165 | } 166 | 167 | placeholderLabel.frame = CGRect(x: originX, y: textRect.height - placeholderLabel.bounds.height - placeholderInsets.y, 168 | width: placeholderLabel.bounds.width, height: placeholderLabel.bounds.height) 169 | } 170 | 171 | // MARK: - Overrides 172 | 173 | override open func editingRect(forBounds bounds: CGRect) -> CGRect { 174 | let newBounds = rectForBorder(bounds) 175 | return newBounds.insetBy(dx: textFieldInsets.x, dy: 0) 176 | } 177 | 178 | override open func textRect(forBounds bounds: CGRect) -> CGRect { 179 | let newBounds = rectForBorder(bounds) 180 | return newBounds.insetBy(dx: textFieldInsets.x, dy: 0) 181 | } 182 | 183 | } 184 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/HoshiTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HoshiTextField.swift 3 | // TextFieldEffects 4 | // 5 | // Created by Raúl Riera on 24/01/2015. 6 | // Copyright (c) 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | An HoshiTextField is a subclass of the TextFieldEffects object, is a control that displays an UITextField with a customizable visual effect around the lower edge of the control. 13 | */ 14 | @IBDesignable open class HoshiTextField: TextFieldEffects { 15 | /** 16 | The color of the border when it has no content. 17 | 18 | This property applies a color to the lower edge of the control. The default value for this property is a clear color. 19 | */ 20 | @IBInspectable dynamic open var borderInactiveColor: UIColor? { 21 | didSet { 22 | updateBorder() 23 | } 24 | } 25 | 26 | /** 27 | The color of the border when it has content. 28 | 29 | This property applies a color to the lower edge of the control. The default value for this property is a clear color. 30 | */ 31 | @IBInspectable dynamic open var borderActiveColor: UIColor? { 32 | didSet { 33 | updateBorder() 34 | } 35 | } 36 | 37 | /** 38 | The color of the placeholder text. 39 | 40 | This property applies a color to the complete placeholder string. The default value for this property is a black color. 41 | */ 42 | @IBInspectable dynamic open var placeholderColor: UIColor = .black { 43 | didSet { 44 | updatePlaceholder() 45 | } 46 | } 47 | 48 | /** 49 | The scale of the placeholder font. 50 | 51 | This property determines the size of the placeholder label relative to the font size of the text field. 52 | */ 53 | @IBInspectable dynamic open var placeholderFontScale: CGFloat = 0.65 { 54 | didSet { 55 | updatePlaceholder() 56 | } 57 | } 58 | 59 | override open var placeholder: String? { 60 | didSet { 61 | updatePlaceholder() 62 | } 63 | } 64 | 65 | override open var bounds: CGRect { 66 | didSet { 67 | updateBorder() 68 | updatePlaceholder() 69 | } 70 | } 71 | 72 | private let borderThickness: (active: CGFloat, inactive: CGFloat) = (active: 2, inactive: 0.5) 73 | private let placeholderInsets = CGPoint(x: 0, y: 6) 74 | private let textFieldInsets = CGPoint(x: 0, y: 12) 75 | private let inactiveBorderLayer = CALayer() 76 | private let activeBorderLayer = CALayer() 77 | private var activePlaceholderPoint: CGPoint = CGPoint.zero 78 | 79 | // MARK: - TextFieldEffects 80 | 81 | override open func drawViewsForRect(_ rect: CGRect) { 82 | let frame = CGRect(origin: CGPoint.zero, size: CGSize(width: rect.size.width, height: rect.size.height)) 83 | 84 | placeholderLabel.frame = frame.insetBy(dx: placeholderInsets.x, dy: placeholderInsets.y) 85 | placeholderLabel.font = placeholderFontFromFont(font!) 86 | 87 | updateBorder() 88 | updatePlaceholder() 89 | 90 | layer.addSublayer(inactiveBorderLayer) 91 | layer.addSublayer(activeBorderLayer) 92 | addSubview(placeholderLabel) 93 | } 94 | 95 | override open func animateViewsForTextEntry() { 96 | if text!.isEmpty { 97 | UIView.animate(withDuration: 0.3, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 1.0, options: .beginFromCurrentState, animations: ({ 98 | self.placeholderLabel.frame.origin = CGPoint(x: 10, y: self.placeholderLabel.frame.origin.y) 99 | self.placeholderLabel.alpha = 0 100 | }), completion: { _ in 101 | self.animationCompletionHandler?(.textEntry) 102 | }) 103 | } 104 | 105 | layoutPlaceholderInTextRect() 106 | placeholderLabel.frame.origin = activePlaceholderPoint 107 | 108 | UIView.animate(withDuration: 0.4, animations: { 109 | self.placeholderLabel.alpha = 1.0 110 | }) 111 | 112 | activeBorderLayer.frame = rectForBorder(borderThickness.active, isFilled: true) 113 | } 114 | 115 | override open func animateViewsForTextDisplay() { 116 | if let text = text, text.isEmpty { 117 | UIView.animate(withDuration: 0.35, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 2.0, options: .beginFromCurrentState, animations: ({ 118 | self.layoutPlaceholderInTextRect() 119 | self.placeholderLabel.alpha = 1 120 | }), completion: { _ in 121 | self.animationCompletionHandler?(.textDisplay) 122 | }) 123 | 124 | activeBorderLayer.frame = self.rectForBorder(self.borderThickness.active, isFilled: false) 125 | inactiveBorderLayer.frame = self.rectForBorder(self.borderThickness.inactive, isFilled: true) 126 | 127 | } 128 | } 129 | 130 | // MARK: - Private 131 | 132 | private func updateBorder() { 133 | inactiveBorderLayer.frame = rectForBorder(borderThickness.inactive, isFilled: !isFirstResponder) 134 | inactiveBorderLayer.backgroundColor = borderInactiveColor?.cgColor 135 | 136 | activeBorderLayer.frame = rectForBorder(borderThickness.active, isFilled: isFirstResponder) 137 | activeBorderLayer.backgroundColor = borderActiveColor?.cgColor 138 | } 139 | 140 | private func updatePlaceholder() { 141 | placeholderLabel.text = placeholder 142 | placeholderLabel.textColor = placeholderColor 143 | placeholderLabel.sizeToFit() 144 | layoutPlaceholderInTextRect() 145 | 146 | if isFirstResponder || text!.isNotEmpty { 147 | animateViewsForTextEntry() 148 | } 149 | } 150 | 151 | private func placeholderFontFromFont(_ font: UIFont) -> UIFont! { 152 | let smallerFont = UIFont(descriptor: font.fontDescriptor, size: font.pointSize * placeholderFontScale) 153 | return smallerFont 154 | } 155 | 156 | private func rectForBorder(_ thickness: CGFloat, isFilled: Bool) -> CGRect { 157 | if isFilled { 158 | return CGRect(origin: CGPoint(x: 0, y: frame.height-thickness), size: CGSize(width: frame.width, height: thickness)) 159 | } else { 160 | return CGRect(origin: CGPoint(x: 0, y: frame.height-thickness), size: CGSize(width: 0, height: thickness)) 161 | } 162 | } 163 | 164 | private func layoutPlaceholderInTextRect() { 165 | let textRect = self.textRect(forBounds: bounds) 166 | var originX = textRect.origin.x 167 | switch self.textAlignment { 168 | case .center: 169 | originX += textRect.size.width/2 - placeholderLabel.bounds.width/2 170 | case .right: 171 | originX += textRect.size.width - placeholderLabel.bounds.width 172 | default: 173 | break 174 | } 175 | placeholderLabel.frame = CGRect(x: originX, y: textRect.height/2, 176 | width: placeholderLabel.bounds.width, height: placeholderLabel.bounds.height) 177 | activePlaceholderPoint = CGPoint(x: placeholderLabel.frame.origin.x, y: placeholderLabel.frame.origin.y - placeholderLabel.frame.size.height - placeholderInsets.y) 178 | 179 | } 180 | 181 | // MARK: - Overrides 182 | 183 | override open func editingRect(forBounds bounds: CGRect) -> CGRect { 184 | return bounds.offsetBy(dx: textFieldInsets.x, dy: textFieldInsets.y) 185 | } 186 | 187 | override open func textRect(forBounds bounds: CGRect) -> CGRect { 188 | return bounds.offsetBy(dx: textFieldInsets.x, dy: textFieldInsets.y) 189 | } 190 | 191 | } 192 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/YoshikoTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // YoshikoTextField.swift 3 | // TextFieldEffects 4 | // 5 | // Created by Keenan Cassidy on 01/10/2015. 6 | // Copyright © 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | An YoshikoTextField is a subclass of the TextFieldEffects object, is a control that displays an UITextField with a customizable visual effect around the edges and background of the control. 13 | */ 14 | @IBDesignable open class YoshikoTextField: TextFieldEffects { 15 | private let borderLayer = CALayer() 16 | private let textFieldInsets = CGPoint(x: 6, y: 0) 17 | private let placeHolderInsets = CGPoint(x: 6, y: 0) 18 | 19 | /** 20 | The size of the border. 21 | 22 | This property applies a thickness to the border of the control. The default value for this property is 2 points. 23 | */ 24 | @IBInspectable open var borderSize: CGFloat = 2.0 { 25 | didSet { 26 | updateBorder() 27 | } 28 | } 29 | 30 | /** 31 | The color of the border when it has content. 32 | 33 | This property applies a color to the edges of the control. The default value for this property is a clear color. 34 | */ 35 | @IBInspectable dynamic open var activeBorderColor: UIColor = .clear { 36 | didSet { 37 | updateBorder() 38 | updateBackground() 39 | updatePlaceholder() 40 | } 41 | } 42 | 43 | /** 44 | The color of the border when it has no content. 45 | 46 | This property applies a color to the edges of the control. The default value for this property is a clear color. 47 | */ 48 | @IBInspectable dynamic open var inactiveBorderColor: UIColor = .clear { 49 | didSet { 50 | updateBorder() 51 | updateBackground() 52 | updatePlaceholder() 53 | } 54 | } 55 | 56 | /** 57 | The color of the input's background when it has content. When it's not focused it reverts to the color of the `inactiveBorderColor` 58 | 59 | This property applies a color to the background of the input. 60 | */ 61 | @IBInspectable dynamic open var activeBackgroundColor: UIColor = .clear { 62 | didSet { 63 | updateBackground() 64 | } 65 | } 66 | 67 | /** 68 | The color of the placeholder text. 69 | 70 | This property applies a color to the complete placeholder string. The default value for this property is a dark gray color. 71 | */ 72 | @IBInspectable dynamic open var placeholderColor: UIColor = .darkGray { 73 | didSet { 74 | updatePlaceholder() 75 | } 76 | } 77 | 78 | /** 79 | The scale of the placeholder font. 80 | 81 | This property determines the size of the placeholder label relative to the font size of the text field. 82 | */ 83 | @IBInspectable dynamic open var placeholderFontScale: CGFloat = 0.7 { 84 | didSet { 85 | updatePlaceholder() 86 | } 87 | } 88 | 89 | override open var placeholder: String? { 90 | didSet { 91 | updatePlaceholder() 92 | } 93 | } 94 | 95 | // MARK: Private 96 | 97 | private func updateBorder() { 98 | borderLayer.frame = rectForBounds(bounds) 99 | borderLayer.borderWidth = borderSize 100 | borderLayer.borderColor = (isFirstResponder || text!.isNotEmpty) ? activeBorderColor.cgColor : inactiveBorderColor.cgColor 101 | } 102 | 103 | private func updateBackground() { 104 | if isFirstResponder || text!.isNotEmpty { 105 | borderLayer.backgroundColor = activeBackgroundColor.cgColor 106 | } else { 107 | borderLayer.backgroundColor = inactiveBorderColor.cgColor 108 | } 109 | } 110 | 111 | private func updatePlaceholder() { 112 | placeholderLabel.frame = placeholderRect(forBounds: bounds) 113 | placeholderLabel.text = placeholder 114 | placeholderLabel.textAlignment = textAlignment 115 | 116 | if isFirstResponder || text!.isNotEmpty { 117 | placeholderLabel.font = placeholderFontFromFontAndPercentageOfOriginalSize(font: font!, percentageOfOriginalSize: placeholderFontScale * 0.8) 118 | placeholderLabel.text = placeholder?.uppercased() 119 | placeholderLabel.textColor = activeBorderColor 120 | } else { 121 | placeholderLabel.font = placeholderFontFromFontAndPercentageOfOriginalSize(font: font!, percentageOfOriginalSize: placeholderFontScale) 122 | placeholderLabel.textColor = placeholderColor 123 | } 124 | } 125 | 126 | 127 | private func placeholderFontFromFontAndPercentageOfOriginalSize(font: UIFont, percentageOfOriginalSize: CGFloat) -> UIFont! { 128 | let smallerFont = UIFont(descriptor: font.fontDescriptor, size: font.pointSize * placeholderFontScale) 129 | return smallerFont 130 | } 131 | 132 | private func rectForBounds(_ bounds: CGRect) -> CGRect { 133 | return CGRect(x: bounds.origin.x, y: bounds.origin.y + placeholderHeight, width: bounds.size.width, height: bounds.size.height - placeholderHeight) 134 | } 135 | 136 | private var placeholderHeight : CGFloat { 137 | return placeHolderInsets.y + placeholderFontFromFontAndPercentageOfOriginalSize(font: font!, percentageOfOriginalSize: placeholderFontScale).lineHeight 138 | } 139 | 140 | private func animateViews() { 141 | UIView.animate(withDuration: 0.2, animations: { 142 | // Prevents a "flash" in the placeholder 143 | if self.text!.isEmpty { 144 | self.placeholderLabel.alpha = 0 145 | } 146 | 147 | self.placeholderLabel.frame = self.placeholderRect(forBounds: self.bounds) 148 | 149 | }) { _ in 150 | self.updatePlaceholder() 151 | 152 | UIView.animate(withDuration: 0.3, animations: { 153 | self.placeholderLabel.alpha = 1 154 | self.updateBorder() 155 | self.updateBackground() 156 | }, completion: { _ in 157 | self.animationCompletionHandler?(self.isFirstResponder ? .textEntry : .textDisplay) 158 | }) 159 | } 160 | } 161 | 162 | // MARK: - TextFieldEffects 163 | 164 | override open func animateViewsForTextEntry() { 165 | animateViews() 166 | } 167 | 168 | override open func animateViewsForTextDisplay() { 169 | animateViews() 170 | } 171 | 172 | // MARK: - Overrides 173 | 174 | override open var bounds: CGRect { 175 | didSet { 176 | updatePlaceholder() 177 | updateBorder() 178 | updateBackground() 179 | } 180 | } 181 | 182 | override open func drawViewsForRect(_ rect: CGRect) { 183 | updatePlaceholder() 184 | updateBorder() 185 | updateBackground() 186 | 187 | layer.insertSublayer(borderLayer, at: 0) 188 | addSubview(placeholderLabel) 189 | } 190 | 191 | open override func placeholderRect(forBounds bounds: CGRect) -> CGRect { 192 | if isFirstResponder || text!.isNotEmpty { 193 | return CGRect(x: placeHolderInsets.x, y: placeHolderInsets.y, width: bounds.width, height: placeholderHeight) 194 | } else { 195 | return textRect(forBounds: bounds) 196 | } 197 | } 198 | 199 | open override func editingRect(forBounds bounds: CGRect) -> CGRect { 200 | return textRect(forBounds: bounds) 201 | } 202 | 203 | override open func textRect(forBounds bounds: CGRect) -> CGRect { 204 | return CGRect(x: textFieldInsets.x, 205 | y: placeholderHeight, 206 | width: bounds.width - (textFieldInsets.x * 2), 207 | height: bounds.height - placeholderHeight) 208 | } 209 | 210 | // MARK: - Interface Builder 211 | 212 | open override func prepareForInterfaceBuilder() { 213 | placeholderLabel.alpha = 1 214 | } 215 | 216 | } 217 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects/YokoTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // YokoTextField.swift 3 | // TextFieldEffects 4 | // 5 | // Created by Raúl Riera on 30/01/2015. 6 | // Copyright (c) 2015 Raul Riera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | A YokoTextField is a subclass of the TextFieldEffects object, is a control that displays an UITextField with a customizable 3D visual effect on the background of the control. 13 | */ 14 | @IBDesignable open class YokoTextField: TextFieldEffects { 15 | /** 16 | The color of the placeholder text. 17 | 18 | This property applies a color to the complete placeholder string. The default value for this property is a black color. 19 | */ 20 | @IBInspectable dynamic open var placeholderColor: UIColor? { 21 | didSet { 22 | updatePlaceholder() 23 | } 24 | } 25 | 26 | /** 27 | The scale of the placeholder font. 28 | 29 | This property determines the size of the placeholder label relative to the font size of the text field. 30 | */ 31 | @IBInspectable dynamic open var placeholderFontScale: CGFloat = 0.7 { 32 | didSet { 33 | updatePlaceholder() 34 | } 35 | } 36 | 37 | /** 38 | The view’s foreground color. 39 | 40 | The default value for this property is a clear color. 41 | */ 42 | @IBInspectable dynamic open var foregroundColor: UIColor = .black { 43 | didSet { 44 | updateForeground() 45 | } 46 | } 47 | 48 | override open var placeholder: String? { 49 | didSet { 50 | updatePlaceholder() 51 | } 52 | } 53 | 54 | override open var bounds: CGRect { 55 | didSet { 56 | updateForeground() 57 | updatePlaceholder() 58 | } 59 | } 60 | 61 | private let foregroundView = UIView() 62 | private let foregroundLayer = CALayer() 63 | private let borderThickness: CGFloat = 3 64 | private let placeholderInsets = CGPoint(x: 6, y: 6) 65 | private let textFieldInsets = CGPoint(x: 6, y: 6) 66 | 67 | // MARK: - TextFieldEffects 68 | 69 | override open func drawViewsForRect(_ rect: CGRect) { 70 | updateForeground() 71 | updatePlaceholder() 72 | 73 | insertSubview(foregroundView, at: 0) 74 | addSubview(placeholderLabel) 75 | layer.insertSublayer(foregroundLayer, at: 0) 76 | } 77 | 78 | override open func animateViewsForTextEntry() { 79 | UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.6, options: .beginFromCurrentState, animations: { 80 | 81 | self.foregroundView.layer.transform = CATransform3DIdentity 82 | 83 | }, completion: { _ in 84 | self.animationCompletionHandler?(.textEntry) 85 | }) 86 | 87 | foregroundLayer.frame = rectForBorder(foregroundView.frame, isFilled: false) 88 | } 89 | 90 | override open func animateViewsForTextDisplay() { 91 | if text!.isEmpty { 92 | UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.6, options: .beginFromCurrentState, animations: { 93 | 94 | self.foregroundLayer.frame = self.rectForBorder(self.foregroundView.frame, isFilled: true) 95 | self.foregroundView.layer.transform = self.rotationAndPerspectiveTransformForView(self.foregroundView) 96 | }, completion: { _ in 97 | self.animationCompletionHandler?(.textDisplay) 98 | }) 99 | } 100 | } 101 | 102 | // MARK: - Private 103 | 104 | private func updateForeground() { 105 | foregroundView.frame = rectForForeground(frame) 106 | foregroundView.isUserInteractionEnabled = false 107 | foregroundView.layer.transform = rotationAndPerspectiveTransformForView(foregroundView) 108 | foregroundView.backgroundColor = foregroundColor 109 | 110 | foregroundLayer.borderWidth = borderThickness 111 | foregroundLayer.borderColor = colorWithBrightnessFactor(foregroundColor, factor: 0.8).cgColor 112 | foregroundLayer.frame = rectForBorder(foregroundView.frame, isFilled: true) 113 | } 114 | 115 | private func updatePlaceholder() { 116 | placeholderLabel.font = placeholderFontFromFont(font!) 117 | placeholderLabel.text = placeholder 118 | placeholderLabel.textColor = placeholderColor 119 | placeholderLabel.sizeToFit() 120 | layoutPlaceholderInTextRect() 121 | 122 | if isFirstResponder || text!.isNotEmpty { 123 | animateViewsForTextEntry() 124 | } 125 | } 126 | 127 | private func placeholderFontFromFont(_ font: UIFont) -> UIFont! { 128 | let smallerFont = UIFont(descriptor: font.fontDescriptor, size: font.pointSize * placeholderFontScale) 129 | return smallerFont 130 | } 131 | 132 | private func rectForForeground(_ bounds: CGRect) -> CGRect { 133 | let newRect = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height - font!.lineHeight + textFieldInsets.y - borderThickness) 134 | 135 | return newRect 136 | } 137 | 138 | private func rectForBorder(_ bounds: CGRect, isFilled: Bool) -> CGRect { 139 | var newRect = CGRect(x: 0, y: bounds.size.height, width: bounds.size.width, height: isFilled ? borderThickness : 0) 140 | 141 | if !CATransform3DIsIdentity(foregroundView.layer.transform) { 142 | newRect.origin = CGPoint(x: 0, y: bounds.origin.y) 143 | } 144 | 145 | return newRect 146 | } 147 | 148 | private func layoutPlaceholderInTextRect() { 149 | let textRect = self.textRect(forBounds: bounds) 150 | var originX = textRect.origin.x 151 | switch textAlignment { 152 | case .center: 153 | originX += textRect.size.width/2 - placeholderLabel.bounds.width/2 154 | case .right: 155 | originX += textRect.size.width - placeholderLabel.bounds.width 156 | default: 157 | break 158 | } 159 | placeholderLabel.frame = CGRect(x: originX, y: bounds.height - placeholderLabel.frame.height, 160 | width: placeholderLabel.frame.size.width, height: placeholderLabel.frame.size.height) 161 | } 162 | 163 | // MARK: - 164 | 165 | private func setAnchorPoint(_ anchorPoint:CGPoint, forView view:UIView) { 166 | var newPoint:CGPoint = CGPoint(x: view.bounds.size.width * anchorPoint.x, y: view.bounds.size.height * anchorPoint.y) 167 | var oldPoint:CGPoint = CGPoint(x: view.bounds.size.width * view.layer.anchorPoint.x, y: view.bounds.size.height * view.layer.anchorPoint.y) 168 | 169 | newPoint = newPoint.applying(view.transform) 170 | oldPoint = oldPoint.applying(view.transform) 171 | 172 | var position = view.layer.position 173 | 174 | position.x -= oldPoint.x 175 | position.x += newPoint.x 176 | 177 | position.y -= oldPoint.y 178 | position.y += newPoint.y 179 | 180 | view.layer.position = position 181 | view.layer.anchorPoint = anchorPoint 182 | } 183 | 184 | private func colorWithBrightnessFactor(_ color: UIColor, factor: CGFloat) -> UIColor { 185 | var hue : CGFloat = 0 186 | var saturation : CGFloat = 0 187 | var brightness : CGFloat = 0 188 | var alpha : CGFloat = 0 189 | 190 | if color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) { 191 | return UIColor(hue: hue, saturation: saturation, brightness: brightness * factor, alpha: alpha) 192 | } else { 193 | return color; 194 | } 195 | } 196 | 197 | private func rotationAndPerspectiveTransformForView(_ view: UIView) -> CATransform3D { 198 | setAnchorPoint(CGPoint(x: 0.5, y: 1.0), forView:view) 199 | 200 | var rotationAndPerspectiveTransform = CATransform3DIdentity 201 | rotationAndPerspectiveTransform.m34 = 1.0/800 202 | let radians = ((-90) / 180.0 * CGFloat.pi) 203 | rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, radians, 1.0, 0.0, 0.0) 204 | return rotationAndPerspectiveTransform 205 | } 206 | 207 | // MARK: - Overrides 208 | 209 | override open func editingRect(forBounds bounds: CGRect) -> CGRect { 210 | let newBounds = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height - font!.lineHeight + textFieldInsets.y) 211 | return newBounds.insetBy(dx: textFieldInsets.x, dy: 0) 212 | } 213 | 214 | override open func textRect(forBounds bounds: CGRect) -> CGRect { 215 | let newBounds = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height - font!.lineHeight + textFieldInsets.y) 216 | 217 | return newBounds.insetBy(dx: textFieldInsets.x, dy: 0) 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldEffects.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 11E69DA71B27B1A90025D54E /* AkiraTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E69DA61B27B1A90025D54E /* AkiraTextField.swift */; }; 11 | 4C42C7711AB20C97009BE2A0 /* TextFieldEffects.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4CB3B6CE1AA8DEA7000AFA56 /* TextFieldEffects.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 12 | 4C8036EB1B90A88E00218FAE /* ExampleTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C8036EA1B90A88E00218FAE /* ExampleTableViewController.swift */; }; 13 | 4C86F6A31E8C0085001FB2B3 /* TextFieldEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C86F6A21E8C0085001FB2B3 /* TextFieldEffects.swift */; }; 14 | 4C86F6A41E8C0109001FB2B3 /* TextFieldEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C86F6A21E8C0085001FB2B3 /* TextFieldEffects.swift */; }; 15 | 4CB3B6D31AA8DEA7000AFA56 /* TextFieldEffects.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CB3B6D21AA8DEA7000AFA56 /* TextFieldEffects.h */; settings = {ATTRIBUTES = (Public, ); }; }; 16 | 4CB3B6EF1AA8DEC3000AFA56 /* HoshiTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB3B6E71AA8DEC3000AFA56 /* HoshiTextField.swift */; }; 17 | 4CB3B6F01AA8DEC3000AFA56 /* IsaoTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB3B6E81AA8DEC3000AFA56 /* IsaoTextField.swift */; }; 18 | 4CB3B6F11AA8DEC3000AFA56 /* JiroTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB3B6E91AA8DEC3000AFA56 /* JiroTextField.swift */; }; 19 | 4CB3B6F21AA8DEC3000AFA56 /* KaedeTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB3B6EA1AA8DEC3000AFA56 /* KaedeTextField.swift */; }; 20 | 4CB3B6F31AA8DEC3000AFA56 /* MadokaTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB3B6EB1AA8DEC3000AFA56 /* MadokaTextField.swift */; }; 21 | 4CB3B6F41AA8DEC3000AFA56 /* MinoruTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB3B6EC1AA8DEC3000AFA56 /* MinoruTextField.swift */; }; 22 | 4CB3B6F61AA8DEC3000AFA56 /* YokoTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB3B6EE1AA8DEC3000AFA56 /* YokoTextField.swift */; }; 23 | 4CB3B6F71AA8DED3000AFA56 /* TextFieldEffects.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CB3B6CE1AA8DEA7000AFA56 /* TextFieldEffects.framework */; }; 24 | 4CBF76721A71AF7700073B6A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CBF76711A71AF7700073B6A /* AppDelegate.swift */; }; 25 | 4CBF76771A71AF7700073B6A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4CBF76751A71AF7700073B6A /* Main.storyboard */; }; 26 | 4CBF76791A71AF7700073B6A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4CBF76781A71AF7700073B6A /* Images.xcassets */; }; 27 | 4CBF767C1A71AF7700073B6A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CBF767A1A71AF7700073B6A /* LaunchScreen.xib */; }; 28 | DF983ABB1BBD1F4100BCC4C7 /* YoshikoTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF983ABA1BBD1F4100BCC4C7 /* YoshikoTextField.swift */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | 4C42C7721AB20C97009BE2A0 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 4CBF76421A71AE4500073B6A /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 4CB3B6CD1AA8DEA7000AFA56; 37 | remoteInfo = TextFieldEffects; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXCopyFilesBuildPhase section */ 42 | 4CE3658B1A73CC520021A842 /* Embed Frameworks */ = { 43 | isa = PBXCopyFilesBuildPhase; 44 | buildActionMask = 2147483647; 45 | dstPath = ""; 46 | dstSubfolderSpec = 10; 47 | files = ( 48 | 4C42C7711AB20C97009BE2A0 /* TextFieldEffects.framework in Embed Frameworks */, 49 | ); 50 | name = "Embed Frameworks"; 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXCopyFilesBuildPhase section */ 54 | 55 | /* Begin PBXFileReference section */ 56 | 11E69DA61B27B1A90025D54E /* AkiraTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AkiraTextField.swift; sourceTree = ""; }; 57 | 4C8036EA1B90A88E00218FAE /* ExampleTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleTableViewController.swift; sourceTree = ""; }; 58 | 4C86F6A21E8C0085001FB2B3 /* TextFieldEffects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldEffects.swift; sourceTree = ""; }; 59 | 4CB3B6CE1AA8DEA7000AFA56 /* TextFieldEffects.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TextFieldEffects.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 4CB3B6D11AA8DEA7000AFA56 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | 4CB3B6D21AA8DEA7000AFA56 /* TextFieldEffects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TextFieldEffects.h; sourceTree = ""; }; 62 | 4CB3B6E71AA8DEC3000AFA56 /* HoshiTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HoshiTextField.swift; sourceTree = ""; }; 63 | 4CB3B6E81AA8DEC3000AFA56 /* IsaoTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IsaoTextField.swift; sourceTree = ""; }; 64 | 4CB3B6E91AA8DEC3000AFA56 /* JiroTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JiroTextField.swift; sourceTree = ""; }; 65 | 4CB3B6EA1AA8DEC3000AFA56 /* KaedeTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KaedeTextField.swift; sourceTree = ""; }; 66 | 4CB3B6EB1AA8DEC3000AFA56 /* MadokaTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MadokaTextField.swift; sourceTree = ""; }; 67 | 4CB3B6EC1AA8DEC3000AFA56 /* MinoruTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinoruTextField.swift; sourceTree = ""; }; 68 | 4CB3B6EE1AA8DEC3000AFA56 /* YokoTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = YokoTextField.swift; sourceTree = ""; }; 69 | 4CBF766D1A71AF7700073B6A /* TextFieldsDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TextFieldsDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | 4CBF76701A71AF7700073B6A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 71 | 4CBF76711A71AF7700073B6A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 72 | 4CBF76761A71AF7700073B6A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 73 | 4CBF76781A71AF7700073B6A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 74 | 4CBF767B1A71AF7700073B6A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 75 | DF983ABA1BBD1F4100BCC4C7 /* YoshikoTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = YoshikoTextField.swift; sourceTree = ""; }; 76 | /* End PBXFileReference section */ 77 | 78 | /* Begin PBXFrameworksBuildPhase section */ 79 | 4CB3B6CA1AA8DEA7000AFA56 /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | 4CBF766A1A71AF7700073B6A /* Frameworks */ = { 87 | isa = PBXFrameworksBuildPhase; 88 | buildActionMask = 2147483647; 89 | files = ( 90 | 4CB3B6F71AA8DED3000AFA56 /* TextFieldEffects.framework in Frameworks */, 91 | ); 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | /* End PBXFrameworksBuildPhase section */ 95 | 96 | /* Begin PBXGroup section */ 97 | 4CB3B6CF1AA8DEA7000AFA56 /* TextFieldEffects */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 11E69DA61B27B1A90025D54E /* AkiraTextField.swift */, 101 | 4CB3B6E71AA8DEC3000AFA56 /* HoshiTextField.swift */, 102 | 4CB3B6E81AA8DEC3000AFA56 /* IsaoTextField.swift */, 103 | 4CB3B6E91AA8DEC3000AFA56 /* JiroTextField.swift */, 104 | 4CB3B6EA1AA8DEC3000AFA56 /* KaedeTextField.swift */, 105 | 4CB3B6EB1AA8DEC3000AFA56 /* MadokaTextField.swift */, 106 | 4CB3B6EC1AA8DEC3000AFA56 /* MinoruTextField.swift */, 107 | 4C86F6A21E8C0085001FB2B3 /* TextFieldEffects.swift */, 108 | 4CB3B6EE1AA8DEC3000AFA56 /* YokoTextField.swift */, 109 | DF983ABA1BBD1F4100BCC4C7 /* YoshikoTextField.swift */, 110 | 4CB3B6D21AA8DEA7000AFA56 /* TextFieldEffects.h */, 111 | 4CB3B6D01AA8DEA7000AFA56 /* Supporting Files */, 112 | ); 113 | path = TextFieldEffects; 114 | sourceTree = ""; 115 | }; 116 | 4CB3B6D01AA8DEA7000AFA56 /* Supporting Files */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 4CB3B6D11AA8DEA7000AFA56 /* Info.plist */, 120 | ); 121 | name = "Supporting Files"; 122 | sourceTree = ""; 123 | }; 124 | 4CBF76411A71AE4500073B6A = { 125 | isa = PBXGroup; 126 | children = ( 127 | 4CBF766E1A71AF7700073B6A /* TextFieldsDemo */, 128 | 4CB3B6CF1AA8DEA7000AFA56 /* TextFieldEffects */, 129 | 4CBF764C1A71AE4500073B6A /* Products */, 130 | ); 131 | sourceTree = ""; 132 | }; 133 | 4CBF764C1A71AE4500073B6A /* Products */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 4CBF766D1A71AF7700073B6A /* TextFieldsDemo.app */, 137 | 4CB3B6CE1AA8DEA7000AFA56 /* TextFieldEffects.framework */, 138 | ); 139 | name = Products; 140 | sourceTree = ""; 141 | }; 142 | 4CBF766E1A71AF7700073B6A /* TextFieldsDemo */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 4CBF76711A71AF7700073B6A /* AppDelegate.swift */, 146 | 4C8036EA1B90A88E00218FAE /* ExampleTableViewController.swift */, 147 | 4CBF76751A71AF7700073B6A /* Main.storyboard */, 148 | 4CBF76781A71AF7700073B6A /* Images.xcassets */, 149 | 4CBF767A1A71AF7700073B6A /* LaunchScreen.xib */, 150 | 4CBF766F1A71AF7700073B6A /* Supporting Files */, 151 | ); 152 | path = TextFieldsDemo; 153 | sourceTree = ""; 154 | }; 155 | 4CBF766F1A71AF7700073B6A /* Supporting Files */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 4CBF76701A71AF7700073B6A /* Info.plist */, 159 | ); 160 | name = "Supporting Files"; 161 | sourceTree = ""; 162 | }; 163 | /* End PBXGroup section */ 164 | 165 | /* Begin PBXHeadersBuildPhase section */ 166 | 4CB3B6CB1AA8DEA7000AFA56 /* Headers */ = { 167 | isa = PBXHeadersBuildPhase; 168 | buildActionMask = 2147483647; 169 | files = ( 170 | 4CB3B6D31AA8DEA7000AFA56 /* TextFieldEffects.h in Headers */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | /* End PBXHeadersBuildPhase section */ 175 | 176 | /* Begin PBXNativeTarget section */ 177 | 4CB3B6CD1AA8DEA7000AFA56 /* TextFieldEffects */ = { 178 | isa = PBXNativeTarget; 179 | buildConfigurationList = 4CB3B6E11AA8DEA7000AFA56 /* Build configuration list for PBXNativeTarget "TextFieldEffects" */; 180 | buildPhases = ( 181 | 4CB3B6C91AA8DEA7000AFA56 /* Sources */, 182 | 4CB3B6CA1AA8DEA7000AFA56 /* Frameworks */, 183 | 4CB3B6CB1AA8DEA7000AFA56 /* Headers */, 184 | 4CB3B6CC1AA8DEA7000AFA56 /* Resources */, 185 | ); 186 | buildRules = ( 187 | ); 188 | dependencies = ( 189 | ); 190 | name = TextFieldEffects; 191 | productName = TextFieldEffects; 192 | productReference = 4CB3B6CE1AA8DEA7000AFA56 /* TextFieldEffects.framework */; 193 | productType = "com.apple.product-type.framework"; 194 | }; 195 | 4CBF766C1A71AF7700073B6A /* TextFieldsDemo */ = { 196 | isa = PBXNativeTarget; 197 | buildConfigurationList = 4CBF76891A71AF7800073B6A /* Build configuration list for PBXNativeTarget "TextFieldsDemo" */; 198 | buildPhases = ( 199 | 4CBF76691A71AF7700073B6A /* Sources */, 200 | 4CBF766A1A71AF7700073B6A /* Frameworks */, 201 | 4CBF766B1A71AF7700073B6A /* Resources */, 202 | 4CE3658B1A73CC520021A842 /* Embed Frameworks */, 203 | ); 204 | buildRules = ( 205 | ); 206 | dependencies = ( 207 | 4C42C7731AB20C97009BE2A0 /* PBXTargetDependency */, 208 | ); 209 | name = TextFieldsDemo; 210 | productName = TextFieldsDemo; 211 | productReference = 4CBF766D1A71AF7700073B6A /* TextFieldsDemo.app */; 212 | productType = "com.apple.product-type.application"; 213 | }; 214 | /* End PBXNativeTarget section */ 215 | 216 | /* Begin PBXProject section */ 217 | 4CBF76421A71AE4500073B6A /* Project object */ = { 218 | isa = PBXProject; 219 | attributes = { 220 | LastSwiftUpdateCheck = 0700; 221 | LastUpgradeCheck = 1200; 222 | ORGANIZATIONNAME = "Raul Riera"; 223 | TargetAttributes = { 224 | 4CB3B6CD1AA8DEA7000AFA56 = { 225 | CreatedOnToolsVersion = 6.2; 226 | LastSwiftMigration = 1100; 227 | ProvisioningStyle = Automatic; 228 | }; 229 | 4CBF766C1A71AF7700073B6A = { 230 | CreatedOnToolsVersion = 6.1.1; 231 | DevelopmentTeam = R64MTWS872; 232 | LastSwiftMigration = 1100; 233 | }; 234 | }; 235 | }; 236 | buildConfigurationList = 4CBF76451A71AE4500073B6A /* Build configuration list for PBXProject "TextFieldEffects" */; 237 | compatibilityVersion = "Xcode 3.2"; 238 | developmentRegion = en; 239 | hasScannedForEncodings = 0; 240 | knownRegions = ( 241 | en, 242 | Base, 243 | ); 244 | mainGroup = 4CBF76411A71AE4500073B6A; 245 | productRefGroup = 4CBF764C1A71AE4500073B6A /* Products */; 246 | projectDirPath = ""; 247 | projectRoot = ""; 248 | targets = ( 249 | 4CBF766C1A71AF7700073B6A /* TextFieldsDemo */, 250 | 4CB3B6CD1AA8DEA7000AFA56 /* TextFieldEffects */, 251 | ); 252 | }; 253 | /* End PBXProject section */ 254 | 255 | /* Begin PBXResourcesBuildPhase section */ 256 | 4CB3B6CC1AA8DEA7000AFA56 /* Resources */ = { 257 | isa = PBXResourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | ); 261 | runOnlyForDeploymentPostprocessing = 0; 262 | }; 263 | 4CBF766B1A71AF7700073B6A /* Resources */ = { 264 | isa = PBXResourcesBuildPhase; 265 | buildActionMask = 2147483647; 266 | files = ( 267 | 4CBF76771A71AF7700073B6A /* Main.storyboard in Resources */, 268 | 4CBF767C1A71AF7700073B6A /* LaunchScreen.xib in Resources */, 269 | 4CBF76791A71AF7700073B6A /* Images.xcassets in Resources */, 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | /* End PBXResourcesBuildPhase section */ 274 | 275 | /* Begin PBXSourcesBuildPhase section */ 276 | 4CB3B6C91AA8DEA7000AFA56 /* Sources */ = { 277 | isa = PBXSourcesBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | 4C86F6A41E8C0109001FB2B3 /* TextFieldEffects.swift in Sources */, 281 | DF983ABB1BBD1F4100BCC4C7 /* YoshikoTextField.swift in Sources */, 282 | 4CB3B6F31AA8DEC3000AFA56 /* MadokaTextField.swift in Sources */, 283 | 4CB3B6F61AA8DEC3000AFA56 /* YokoTextField.swift in Sources */, 284 | 4CB3B6EF1AA8DEC3000AFA56 /* HoshiTextField.swift in Sources */, 285 | 4CB3B6F01AA8DEC3000AFA56 /* IsaoTextField.swift in Sources */, 286 | 4CB3B6F21AA8DEC3000AFA56 /* KaedeTextField.swift in Sources */, 287 | 11E69DA71B27B1A90025D54E /* AkiraTextField.swift in Sources */, 288 | 4CB3B6F11AA8DEC3000AFA56 /* JiroTextField.swift in Sources */, 289 | 4CB3B6F41AA8DEC3000AFA56 /* MinoruTextField.swift in Sources */, 290 | ); 291 | runOnlyForDeploymentPostprocessing = 0; 292 | }; 293 | 4CBF76691A71AF7700073B6A /* Sources */ = { 294 | isa = PBXSourcesBuildPhase; 295 | buildActionMask = 2147483647; 296 | files = ( 297 | 4C8036EB1B90A88E00218FAE /* ExampleTableViewController.swift in Sources */, 298 | 4CBF76721A71AF7700073B6A /* AppDelegate.swift in Sources */, 299 | 4C86F6A31E8C0085001FB2B3 /* TextFieldEffects.swift in Sources */, 300 | ); 301 | runOnlyForDeploymentPostprocessing = 0; 302 | }; 303 | /* End PBXSourcesBuildPhase section */ 304 | 305 | /* Begin PBXTargetDependency section */ 306 | 4C42C7731AB20C97009BE2A0 /* PBXTargetDependency */ = { 307 | isa = PBXTargetDependency; 308 | target = 4CB3B6CD1AA8DEA7000AFA56 /* TextFieldEffects */; 309 | targetProxy = 4C42C7721AB20C97009BE2A0 /* PBXContainerItemProxy */; 310 | }; 311 | /* End PBXTargetDependency section */ 312 | 313 | /* Begin PBXVariantGroup section */ 314 | 4CBF76751A71AF7700073B6A /* Main.storyboard */ = { 315 | isa = PBXVariantGroup; 316 | children = ( 317 | 4CBF76761A71AF7700073B6A /* Base */, 318 | ); 319 | name = Main.storyboard; 320 | sourceTree = ""; 321 | }; 322 | 4CBF767A1A71AF7700073B6A /* LaunchScreen.xib */ = { 323 | isa = PBXVariantGroup; 324 | children = ( 325 | 4CBF767B1A71AF7700073B6A /* Base */, 326 | ); 327 | name = LaunchScreen.xib; 328 | sourceTree = ""; 329 | }; 330 | /* End PBXVariantGroup section */ 331 | 332 | /* Begin XCBuildConfiguration section */ 333 | 4CB3B6E21AA8DEA7000AFA56 /* Debug */ = { 334 | isa = XCBuildConfiguration; 335 | buildSettings = { 336 | CLANG_ENABLE_MODULES = YES; 337 | CODE_SIGN_IDENTITY = ""; 338 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 339 | CODE_SIGN_STYLE = Automatic; 340 | DEFINES_MODULE = YES; 341 | DEVELOPMENT_TEAM = ""; 342 | DYLIB_COMPATIBILITY_VERSION = 1; 343 | DYLIB_CURRENT_VERSION = 1; 344 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 345 | GCC_PREPROCESSOR_DEFINITIONS = ( 346 | "DEBUG=1", 347 | "$(inherited)", 348 | ); 349 | INFOPLIST_FILE = TextFieldEffects/Info.plist; 350 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 351 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 352 | PRODUCT_BUNDLE_IDENTIFIER = "com.raulriera.$(PRODUCT_NAME:rfc1034identifier)"; 353 | PRODUCT_NAME = "$(TARGET_NAME)"; 354 | PROVISIONING_PROFILE_SPECIFIER = ""; 355 | SKIP_INSTALL = YES; 356 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 357 | SWIFT_VERSION = 5.0; 358 | }; 359 | name = Debug; 360 | }; 361 | 4CB3B6E31AA8DEA7000AFA56 /* Release */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | CLANG_ENABLE_MODULES = YES; 365 | CODE_SIGN_IDENTITY = ""; 366 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 367 | CODE_SIGN_STYLE = Automatic; 368 | COPY_PHASE_STRIP = NO; 369 | DEFINES_MODULE = YES; 370 | DEVELOPMENT_TEAM = ""; 371 | DYLIB_COMPATIBILITY_VERSION = 1; 372 | DYLIB_CURRENT_VERSION = 1; 373 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 374 | INFOPLIST_FILE = TextFieldEffects/Info.plist; 375 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 376 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 377 | PRODUCT_BUNDLE_IDENTIFIER = "com.raulriera.$(PRODUCT_NAME:rfc1034identifier)"; 378 | PRODUCT_NAME = "$(TARGET_NAME)"; 379 | PROVISIONING_PROFILE_SPECIFIER = ""; 380 | SKIP_INSTALL = YES; 381 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 382 | SWIFT_VERSION = 5.0; 383 | }; 384 | name = Release; 385 | }; 386 | 4CBF765F1A71AE4500073B6A /* Debug */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | ALWAYS_SEARCH_USER_PATHS = NO; 390 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 391 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 392 | CLANG_CXX_LIBRARY = "libc++"; 393 | CLANG_ENABLE_MODULES = YES; 394 | CLANG_ENABLE_OBJC_ARC = YES; 395 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 396 | CLANG_WARN_BOOL_CONVERSION = YES; 397 | CLANG_WARN_COMMA = YES; 398 | CLANG_WARN_CONSTANT_CONVERSION = YES; 399 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 400 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 401 | CLANG_WARN_EMPTY_BODY = YES; 402 | CLANG_WARN_ENUM_CONVERSION = YES; 403 | CLANG_WARN_INFINITE_RECURSION = YES; 404 | CLANG_WARN_INT_CONVERSION = YES; 405 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 406 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 407 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 408 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 409 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 410 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 411 | CLANG_WARN_STRICT_PROTOTYPES = YES; 412 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 413 | CLANG_WARN_UNREACHABLE_CODE = YES; 414 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 415 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 416 | COPY_PHASE_STRIP = NO; 417 | CURRENT_PROJECT_VERSION = 1; 418 | ENABLE_STRICT_OBJC_MSGSEND = YES; 419 | ENABLE_TESTABILITY = YES; 420 | GCC_C_LANGUAGE_STANDARD = gnu99; 421 | GCC_DYNAMIC_NO_PIC = NO; 422 | GCC_NO_COMMON_BLOCKS = YES; 423 | GCC_OPTIMIZATION_LEVEL = 0; 424 | GCC_PREPROCESSOR_DEFINITIONS = ( 425 | "DEBUG=1", 426 | "$(inherited)", 427 | ); 428 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 429 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 430 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 431 | GCC_WARN_UNDECLARED_SELECTOR = YES; 432 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 433 | GCC_WARN_UNUSED_FUNCTION = YES; 434 | GCC_WARN_UNUSED_VARIABLE = YES; 435 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 436 | MTL_ENABLE_DEBUG_INFO = YES; 437 | ONLY_ACTIVE_ARCH = YES; 438 | SDKROOT = iphoneos; 439 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 440 | SWIFT_VERSION = 4.2; 441 | TARGETED_DEVICE_FAMILY = "1,2"; 442 | VERSIONING_SYSTEM = "apple-generic"; 443 | VERSION_INFO_PREFIX = ""; 444 | }; 445 | name = Debug; 446 | }; 447 | 4CBF76601A71AE4500073B6A /* Release */ = { 448 | isa = XCBuildConfiguration; 449 | buildSettings = { 450 | ALWAYS_SEARCH_USER_PATHS = NO; 451 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 452 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 453 | CLANG_CXX_LIBRARY = "libc++"; 454 | CLANG_ENABLE_MODULES = YES; 455 | CLANG_ENABLE_OBJC_ARC = YES; 456 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 457 | CLANG_WARN_BOOL_CONVERSION = YES; 458 | CLANG_WARN_COMMA = YES; 459 | CLANG_WARN_CONSTANT_CONVERSION = YES; 460 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 461 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 462 | CLANG_WARN_EMPTY_BODY = YES; 463 | CLANG_WARN_ENUM_CONVERSION = YES; 464 | CLANG_WARN_INFINITE_RECURSION = YES; 465 | CLANG_WARN_INT_CONVERSION = YES; 466 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 467 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 468 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 469 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 470 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 471 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 472 | CLANG_WARN_STRICT_PROTOTYPES = YES; 473 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 474 | CLANG_WARN_UNREACHABLE_CODE = YES; 475 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 476 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 477 | COPY_PHASE_STRIP = YES; 478 | CURRENT_PROJECT_VERSION = 1; 479 | ENABLE_NS_ASSERTIONS = NO; 480 | ENABLE_STRICT_OBJC_MSGSEND = YES; 481 | GCC_C_LANGUAGE_STANDARD = gnu99; 482 | GCC_NO_COMMON_BLOCKS = YES; 483 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 484 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 485 | GCC_WARN_UNDECLARED_SELECTOR = YES; 486 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 487 | GCC_WARN_UNUSED_FUNCTION = YES; 488 | GCC_WARN_UNUSED_VARIABLE = YES; 489 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 490 | MTL_ENABLE_DEBUG_INFO = NO; 491 | SDKROOT = iphoneos; 492 | SWIFT_VERSION = 4.2; 493 | TARGETED_DEVICE_FAMILY = "1,2"; 494 | VALIDATE_PRODUCT = YES; 495 | VERSIONING_SYSTEM = "apple-generic"; 496 | VERSION_INFO_PREFIX = ""; 497 | }; 498 | name = Release; 499 | }; 500 | 4CBF768A1A71AF7800073B6A /* Debug */ = { 501 | isa = XCBuildConfiguration; 502 | buildSettings = { 503 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 504 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 505 | DEVELOPMENT_TEAM = R64MTWS872; 506 | GCC_PREPROCESSOR_DEFINITIONS = ( 507 | "DEBUG=1", 508 | "$(inherited)", 509 | ); 510 | INFOPLIST_FILE = TextFieldsDemo/Info.plist; 511 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 512 | PRODUCT_BUNDLE_IDENTIFIER = "com.raulriera.$(PRODUCT_NAME:rfc1034identifier)"; 513 | PRODUCT_NAME = "$(TARGET_NAME)"; 514 | SWIFT_VERSION = 5.0; 515 | }; 516 | name = Debug; 517 | }; 518 | 4CBF768B1A71AF7800073B6A /* Release */ = { 519 | isa = XCBuildConfiguration; 520 | buildSettings = { 521 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 522 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 523 | DEVELOPMENT_TEAM = R64MTWS872; 524 | INFOPLIST_FILE = TextFieldsDemo/Info.plist; 525 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 526 | PRODUCT_BUNDLE_IDENTIFIER = "com.raulriera.$(PRODUCT_NAME:rfc1034identifier)"; 527 | PRODUCT_NAME = "$(TARGET_NAME)"; 528 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 529 | SWIFT_VERSION = 5.0; 530 | }; 531 | name = Release; 532 | }; 533 | /* End XCBuildConfiguration section */ 534 | 535 | /* Begin XCConfigurationList section */ 536 | 4CB3B6E11AA8DEA7000AFA56 /* Build configuration list for PBXNativeTarget "TextFieldEffects" */ = { 537 | isa = XCConfigurationList; 538 | buildConfigurations = ( 539 | 4CB3B6E21AA8DEA7000AFA56 /* Debug */, 540 | 4CB3B6E31AA8DEA7000AFA56 /* Release */, 541 | ); 542 | defaultConfigurationIsVisible = 0; 543 | defaultConfigurationName = Release; 544 | }; 545 | 4CBF76451A71AE4500073B6A /* Build configuration list for PBXProject "TextFieldEffects" */ = { 546 | isa = XCConfigurationList; 547 | buildConfigurations = ( 548 | 4CBF765F1A71AE4500073B6A /* Debug */, 549 | 4CBF76601A71AE4500073B6A /* Release */, 550 | ); 551 | defaultConfigurationIsVisible = 0; 552 | defaultConfigurationName = Release; 553 | }; 554 | 4CBF76891A71AF7800073B6A /* Build configuration list for PBXNativeTarget "TextFieldsDemo" */ = { 555 | isa = XCConfigurationList; 556 | buildConfigurations = ( 557 | 4CBF768A1A71AF7800073B6A /* Debug */, 558 | 4CBF768B1A71AF7800073B6A /* Release */, 559 | ); 560 | defaultConfigurationIsVisible = 0; 561 | defaultConfigurationName = Release; 562 | }; 563 | /* End XCConfigurationList section */ 564 | }; 565 | rootObject = 4CBF76421A71AE4500073B6A /* Project object */; 566 | } 567 | -------------------------------------------------------------------------------- /TextFieldEffects/TextFieldsDemo/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 | 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 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | --------------------------------------------------------------------------------