├── .gitignore ├── .swift-version ├── .swiftlint.yml ├── .travis.yml ├── CustomKeyboardTextField.podspec ├── CustomKeyboardTextField.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── CustomKeyboardTextField.xcscheme │ ├── CustomKeyboardTextFieldDemo.xcscheme │ └── CustomKeyboardTextFieldTests.xcscheme ├── CustomKeyboardTextFieldDemo ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── CustomKeyboard.swift ├── GamePadKeyboardView.xib ├── Images │ ├── Bulbasaur.png │ ├── Charmander.png │ └── Squirtle.png ├── Info.plist └── ViewController.swift ├── Documentation └── Image │ ├── custom.png │ ├── date_picker.png │ ├── demo.gif │ └── picker.png ├── Gemfile ├── Gemfile.lock ├── LICENSE.md ├── README.md ├── Sources ├── CustomKeyboardProvider.swift ├── CustomKeyboardTextField.h ├── CustomKeyboardTextField.swift ├── Info.plist └── Keyboards │ ├── ToolbarAccessoryView.swift │ ├── UIDatePickerKeyboard.swift │ └── UIPickerViewKeyboard.swift ├── Tests └── CustomKeyboardTextField │ ├── Info.plist │ ├── UIDatePickerKeyboardTests.swift │ └── UIPickerViewKeyboardTests.swift ├── codecov.yml └── fastlane ├── Fastfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/d1caffed352607b5415e9e0e827f4770eb39e316/Swift.gitignore 2 | 3 | # Xcode 4 | # 5 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 6 | 7 | ## Build generated 8 | build/ 9 | DerivedData/ 10 | 11 | ## Various settings 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata/ 21 | 22 | ## Other 23 | *.moved-aside 24 | *.xcuserstate 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | ## Playgrounds 33 | timeline.xctimeline 34 | playground.xcworkspace 35 | 36 | # Swift Package Manager 37 | # 38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 39 | # Packages/ 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | fastlane/build 69 | 70 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Sources 3 | - Tests/CustomKeyboardTextField 4 | - CustomKeyboardTextFieldDemo 5 | disabled_rules: 6 | - line_length 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | env: 2 | global: 3 | - LC_CTYPE=en_US.UTF-8 4 | - secure: yKRlKg8ya0pvWnYZ516Tq91Jv6/hALM8ItX9Pf6jjmx+H96/MJlaw+xZHUllfzcYyNLOpUGs7eHXwNuZ2YQ+UKcgXwo6YXbIsS27i83zsiMVKeinRx4B0xfU9pqWmz3YOEHUSRtXErvSQn7iiErIqLKvE+C0m9KYKFOeOsJ5FRdts7ZDesEUmyBRnsR85GjZABbwLRbvpYX9ZevPG/dC3TxeK833uTZkRQV9KxINnzLBu8HXoj4WNfwoibqrWPqLYTt4SWyBZ+0AabfUOSId6W4cW9NVhshJA12LWFD7oj7K8onox4IHfZaYToJeafGKKfZDRl8e1g/wP7mSf7uQ+IMoNAUBnO6UY/jTrprfGOiOWoGM7lhuS+ZfPrWUtmUBbT0rc45YibDcXCcGFOcQrcIz7ZK+7OYmkyKUQfCBnqBtpuJ4lIiJd6P/VsrTbvtVeprZKPXNaIqQty7zezcqSRjRqLSLIsP8CQ4LYJkIAxYQ9JVTvyeimT2LBzkv9Nbdxf3ZbskcnsKkSyUyCSQWgcsvX6wKKpF1o1REodDzHn3eHjQ/kYCL3RK/VkL1WJeba6SRKXN+M5MXuJs6AIyJXkLOdPpQp/nLGRfhbKiIjZtN0fzSp6tsVQGC1DeWOiXuS0dXQjV6+wAVZPvFcLxtR4kN0u2ZI0K5k3kp1gspdwc= 5 | - secure: Xuh1dMd/vkDkech5sjM184te8VVRsQZod/JfoC567vqya5ELHoYE37sOCXkOTjGIrywYF+/E2RIfMRy50L1QgW69k52Ubvqa1XBGykilVLNC4ik9+9zjHL3xNM7LfZk5mtGtBeSjBrBfbD2UAKl8cPm3rIN9Zhi/G4K7vyeZdh0sqJRsvPgO1ovU41HeXPAjhheQJEszE5c+mGmD+6lBJOL+2ZYAyZKDpgKnPqNiCwioA1Ct7b9mfuArpB24TVwpJNAIvNXc7xUC9/aApWxTQ68jBOnR86QPsNZ574XWGe9Rvm9lP4M2JirRwuzUQgVPTVN9IVMwGk8t6wWwFF4TW3t4ntX485TlwgxfakaPb6Gr1RhBF8g+yOumIqRKCsYtSFcYePwR/BseeaeRVfIDgAsoBkw5i9GKPCe6gYKt/ETFckCoKguABYodqvbs/wNeM+FCb5jiOwkvgPTIBE8u3o5fgOfHuEgVfLIw6Toh3uS1svjTyLjtkz0unfUEibMmkz0DDgzkRpVaD0wyMRpxO05XiEv2VqAZlo7avVmPlSzT3jD39cVlkOSM9oBlhxM99wHaQO7pDxtK8UZ+zS13priGSLObDCP1l5wfKwSHPplLppbaOFR5fxbuPNOl+wbJgA6pgmd/RIRA9DBKYd556hNFCurmU+R0/usgFFowb8A= 6 | matrix: 7 | include: 8 | - os: osx 9 | language: objective-c 10 | osx_image: xcode8.1 11 | before_install: 12 | - bundle install 13 | - brew install swiftlint 14 | script: 15 | - pod spec lint 16 | - swiftlint 17 | - set -o pipefail && xcodebuild test -project CustomKeyboardTextField.xcodeproj -scheme CustomKeyboardTextFieldTests -destination 'platform=iOS Simulator,name=iPhone 6s' | xcpretty -c 18 | - set -o pipefail && xcodebuild build -project CustomKeyboardTextField.xcodeproj -scheme CustomKeyboardTextFieldDemo -destination 'platform=iOS Simulator,name=iPhone 6s' | xcpretty -c 19 | - bundle exec fastlane deploy_to_appetize 20 | after_success: 21 | - bash <(curl -s https://codecov.io/bash) -J 'CustomKeyboardTextField' 22 | -------------------------------------------------------------------------------- /CustomKeyboardTextField.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "CustomKeyboardTextField" 3 | s.version = "0.3" 4 | s.summary = "Provides easy way to make type safety TextField with custom keyboards." 5 | 6 | s.description = <<-DESC 7 | CustomKeyboardTextField provides easy way to make type safety TextField with custom keyboards. 8 | DESC 9 | 10 | s.homepage = "https://github.com/giginet/CustomKeyboardTextField" 11 | s.screenshots = "https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/master/Documentation/Image/demo.gif" 12 | s.license = { :type => "MIT", :file => "LICENSE.md" } 13 | 14 | s.author = { "giginet" => "giginet.net@gmail.com" } 15 | s.social_media_url = "http://twitter.com/giginet" 16 | s.platform = :ios 17 | s.platform = :ios, "8.0" 18 | 19 | s.source = { :git => "https://github.com/giginet/CustomKeyboardTextField.git", :tag => "#{s.version}" } 20 | 21 | s.source_files = "Sources", "Sources/**/*.{h,swift}" 22 | 23 | s.public_header_files = "Sources/**/*.h" 24 | 25 | s.requires_arc = true 26 | end 27 | -------------------------------------------------------------------------------- /CustomKeyboardTextField.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 073F47561D55FC6F00865351 /* Bulbasaur.png in Resources */ = {isa = PBXBuildFile; fileRef = 073F47531D55FC6F00865351 /* Bulbasaur.png */; }; 11 | 073F47571D55FC6F00865351 /* Charmander.png in Resources */ = {isa = PBXBuildFile; fileRef = 073F47541D55FC6F00865351 /* Charmander.png */; }; 12 | 073F47581D55FC6F00865351 /* Squirtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 073F47551D55FC6F00865351 /* Squirtle.png */; }; 13 | 075E52FD1D56187800E56723 /* UIPickerViewKeyboardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 075E52FC1D56187800E56723 /* UIPickerViewKeyboardTests.swift */; }; 14 | 075E53061D56188C00E56723 /* CustomKeyboardTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = 075E52FF1D56188C00E56723 /* CustomKeyboardTextField.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | 075E53071D56188C00E56723 /* CustomKeyboardTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 075E53001D56188C00E56723 /* CustomKeyboardTextField.swift */; }; 16 | 075E53081D56188C00E56723 /* CustomKeyboardProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 075E53011D56188C00E56723 /* CustomKeyboardProvider.swift */; }; 17 | 075E53091D56188C00E56723 /* ToolbarAccessoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 075E53031D56188C00E56723 /* ToolbarAccessoryView.swift */; }; 18 | 075E530A1D56188C00E56723 /* UIDatePickerKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 075E53041D56188C00E56723 /* UIDatePickerKeyboard.swift */; }; 19 | 075E530B1D56188C00E56723 /* UIPickerViewKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 075E53051D56188C00E56723 /* UIPickerViewKeyboard.swift */; }; 20 | 075E530E1D561C9D00E56723 /* UIDatePickerKeyboardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 075E530D1D561C9D00E56723 /* UIDatePickerKeyboardTests.swift */; }; 21 | 075E530F1D562C5900E56723 /* CustomKeyboardTextField.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07C541F71D54DD880069498C /* CustomKeyboardTextField.framework */; }; 22 | 075E53101D562C5900E56723 /* CustomKeyboardTextField.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 07C541F71D54DD880069498C /* CustomKeyboardTextField.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 23 | 07BA1CBB1D55BF8A00BB2E85 /* CustomKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07BA1CBA1D55BF8A00BB2E85 /* CustomKeyboard.swift */; }; 24 | 07BA1CBD1D55BFAA00BB2E85 /* GamePadKeyboardView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 07BA1CBC1D55BFAA00BB2E85 /* GamePadKeyboardView.xib */; }; 25 | 07C542021D54DD880069498C /* CustomKeyboardTextField.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07C541F71D54DD880069498C /* CustomKeyboardTextField.framework */; }; 26 | 07C5E9A91D54E23C0042C657 /* CustomKeyboardTextField.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07C541F71D54DD880069498C /* CustomKeyboardTextField.framework */; }; 27 | 07C5E9B31D54E2790042C657 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07C5E9AB1D54E2790042C657 /* AppDelegate.swift */; }; 28 | 07C5E9B41D54E2790042C657 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 07C5E9AC1D54E2790042C657 /* Assets.xcassets */; }; 29 | 07C5E9B51D54E2790042C657 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 07C5E9AD1D54E2790042C657 /* LaunchScreen.storyboard */; }; 30 | 07C5E9B61D54E2790042C657 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 07C5E9AF1D54E2790042C657 /* Main.storyboard */; }; 31 | 07C5E9B81D54E2790042C657 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07C5E9B21D54E2790042C657 /* ViewController.swift */; }; 32 | /* End PBXBuildFile section */ 33 | 34 | /* Begin PBXContainerItemProxy section */ 35 | 075E53111D562C5900E56723 /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = 07C541EE1D54DD880069498C /* Project object */; 38 | proxyType = 1; 39 | remoteGlobalIDString = 07C541F61D54DD880069498C; 40 | remoteInfo = CustomKeyboardTextField; 41 | }; 42 | 07C542031D54DD880069498C /* PBXContainerItemProxy */ = { 43 | isa = PBXContainerItemProxy; 44 | containerPortal = 07C541EE1D54DD880069498C /* Project object */; 45 | proxyType = 1; 46 | remoteGlobalIDString = 07C541F61D54DD880069498C; 47 | remoteInfo = CustomKeyboardTextField; 48 | }; 49 | /* End PBXContainerItemProxy section */ 50 | 51 | /* Begin PBXCopyFilesBuildPhase section */ 52 | 075E53131D562C5900E56723 /* Embed Frameworks */ = { 53 | isa = PBXCopyFilesBuildPhase; 54 | buildActionMask = 2147483647; 55 | dstPath = ""; 56 | dstSubfolderSpec = 10; 57 | files = ( 58 | 075E53101D562C5900E56723 /* CustomKeyboardTextField.framework in Embed Frameworks */, 59 | ); 60 | name = "Embed Frameworks"; 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXCopyFilesBuildPhase section */ 64 | 65 | /* Begin PBXFileReference section */ 66 | 073F47531D55FC6F00865351 /* Bulbasaur.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Bulbasaur.png; sourceTree = ""; }; 67 | 073F47541D55FC6F00865351 /* Charmander.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Charmander.png; sourceTree = ""; }; 68 | 073F47551D55FC6F00865351 /* Squirtle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Squirtle.png; sourceTree = ""; }; 69 | 075E52FC1D56187800E56723 /* UIPickerViewKeyboardTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UIPickerViewKeyboardTests.swift; path = Tests/CustomKeyboardTextField/UIPickerViewKeyboardTests.swift; sourceTree = SOURCE_ROOT; }; 70 | 075E52FE1D56187D00E56723 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/CustomKeyboardTextField/Info.plist; sourceTree = SOURCE_ROOT; }; 71 | 075E52FF1D56188C00E56723 /* CustomKeyboardTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CustomKeyboardTextField.h; path = Sources/CustomKeyboardTextField.h; sourceTree = SOURCE_ROOT; }; 72 | 075E53001D56188C00E56723 /* CustomKeyboardTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CustomKeyboardTextField.swift; path = Sources/CustomKeyboardTextField.swift; sourceTree = SOURCE_ROOT; }; 73 | 075E53011D56188C00E56723 /* CustomKeyboardProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CustomKeyboardProvider.swift; path = Sources/CustomKeyboardProvider.swift; sourceTree = SOURCE_ROOT; }; 74 | 075E53031D56188C00E56723 /* ToolbarAccessoryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarAccessoryView.swift; sourceTree = ""; }; 75 | 075E53041D56188C00E56723 /* UIDatePickerKeyboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIDatePickerKeyboard.swift; sourceTree = ""; }; 76 | 075E53051D56188C00E56723 /* UIPickerViewKeyboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIPickerViewKeyboard.swift; sourceTree = ""; }; 77 | 075E530C1D56189200E56723 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = SOURCE_ROOT; }; 78 | 075E530D1D561C9D00E56723 /* UIDatePickerKeyboardTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UIDatePickerKeyboardTests.swift; path = Tests/CustomKeyboardTextField/UIDatePickerKeyboardTests.swift; sourceTree = SOURCE_ROOT; }; 79 | 07BA1CBA1D55BF8A00BB2E85 /* CustomKeyboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomKeyboard.swift; sourceTree = ""; }; 80 | 07BA1CBC1D55BFAA00BB2E85 /* GamePadKeyboardView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = GamePadKeyboardView.xib; sourceTree = ""; }; 81 | 07C541F71D54DD880069498C /* CustomKeyboardTextField.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CustomKeyboardTextField.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 82 | 07C542011D54DD880069498C /* CustomKeyboardTextFieldTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CustomKeyboardTextFieldTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 83 | 07C5E98F1D54E0720042C657 /* CustomKeyboardTextFieldDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CustomKeyboardTextFieldDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | 07C5E9AB1D54E2790042C657 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 85 | 07C5E9AC1D54E2790042C657 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 86 | 07C5E9AE1D54E2790042C657 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 87 | 07C5E9B01D54E2790042C657 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 88 | 07C5E9B11D54E2790042C657 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 89 | 07C5E9B21D54E2790042C657 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 90 | /* End PBXFileReference section */ 91 | 92 | /* Begin PBXFrameworksBuildPhase section */ 93 | 07C541F31D54DD880069498C /* Frameworks */ = { 94 | isa = PBXFrameworksBuildPhase; 95 | buildActionMask = 2147483647; 96 | files = ( 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | 07C541FE1D54DD880069498C /* Frameworks */ = { 101 | isa = PBXFrameworksBuildPhase; 102 | buildActionMask = 2147483647; 103 | files = ( 104 | 07C542021D54DD880069498C /* CustomKeyboardTextField.framework in Frameworks */, 105 | ); 106 | runOnlyForDeploymentPostprocessing = 0; 107 | }; 108 | 07C5E98C1D54E0720042C657 /* Frameworks */ = { 109 | isa = PBXFrameworksBuildPhase; 110 | buildActionMask = 2147483647; 111 | files = ( 112 | 075E530F1D562C5900E56723 /* CustomKeyboardTextField.framework in Frameworks */, 113 | 07C5E9A91D54E23C0042C657 /* CustomKeyboardTextField.framework in Frameworks */, 114 | ); 115 | runOnlyForDeploymentPostprocessing = 0; 116 | }; 117 | /* End PBXFrameworksBuildPhase section */ 118 | 119 | /* Begin PBXGroup section */ 120 | 073F47521D55FC6F00865351 /* Images */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 073F47531D55FC6F00865351 /* Bulbasaur.png */, 124 | 073F47541D55FC6F00865351 /* Charmander.png */, 125 | 073F47551D55FC6F00865351 /* Squirtle.png */, 126 | ); 127 | path = Images; 128 | sourceTree = ""; 129 | }; 130 | 075E53021D56188C00E56723 /* Keyboards */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 075E53031D56188C00E56723 /* ToolbarAccessoryView.swift */, 134 | 075E53041D56188C00E56723 /* UIDatePickerKeyboard.swift */, 135 | 075E53051D56188C00E56723 /* UIPickerViewKeyboard.swift */, 136 | ); 137 | name = Keyboards; 138 | path = Sources/Keyboards; 139 | sourceTree = SOURCE_ROOT; 140 | }; 141 | 07C541ED1D54DD880069498C = { 142 | isa = PBXGroup; 143 | children = ( 144 | 07C541F91D54DD880069498C /* CustomKeyboardTextField */, 145 | 07C542051D54DD890069498C /* CustomKeyboardTextFieldTests */, 146 | 07C5E9AA1D54E2790042C657 /* CustomKeyboardTextFieldDemo */, 147 | 07C541F81D54DD880069498C /* Products */, 148 | ); 149 | sourceTree = ""; 150 | }; 151 | 07C541F81D54DD880069498C /* Products */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | 07C541F71D54DD880069498C /* CustomKeyboardTextField.framework */, 155 | 07C542011D54DD880069498C /* CustomKeyboardTextFieldTests.xctest */, 156 | 07C5E98F1D54E0720042C657 /* CustomKeyboardTextFieldDemo.app */, 157 | ); 158 | name = Products; 159 | sourceTree = ""; 160 | }; 161 | 07C541F91D54DD880069498C /* CustomKeyboardTextField */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | 075E530C1D56189200E56723 /* Info.plist */, 165 | 075E52FF1D56188C00E56723 /* CustomKeyboardTextField.h */, 166 | 075E53001D56188C00E56723 /* CustomKeyboardTextField.swift */, 167 | 075E53011D56188C00E56723 /* CustomKeyboardProvider.swift */, 168 | 075E53021D56188C00E56723 /* Keyboards */, 169 | ); 170 | path = CustomKeyboardTextField; 171 | sourceTree = ""; 172 | }; 173 | 07C542051D54DD890069498C /* CustomKeyboardTextFieldTests */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | 075E52FC1D56187800E56723 /* UIPickerViewKeyboardTests.swift */, 177 | 075E530D1D561C9D00E56723 /* UIDatePickerKeyboardTests.swift */, 178 | 075E52FE1D56187D00E56723 /* Info.plist */, 179 | ); 180 | path = CustomKeyboardTextFieldTests; 181 | sourceTree = ""; 182 | }; 183 | 07C5E9AA1D54E2790042C657 /* CustomKeyboardTextFieldDemo */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 073F47521D55FC6F00865351 /* Images */, 187 | 07C5E9AB1D54E2790042C657 /* AppDelegate.swift */, 188 | 07C5E9AC1D54E2790042C657 /* Assets.xcassets */, 189 | 07C5E9AD1D54E2790042C657 /* LaunchScreen.storyboard */, 190 | 07C5E9AF1D54E2790042C657 /* Main.storyboard */, 191 | 07C5E9B11D54E2790042C657 /* Info.plist */, 192 | 07C5E9B21D54E2790042C657 /* ViewController.swift */, 193 | 07BA1CBA1D55BF8A00BB2E85 /* CustomKeyboard.swift */, 194 | 07BA1CBC1D55BFAA00BB2E85 /* GamePadKeyboardView.xib */, 195 | ); 196 | path = CustomKeyboardTextFieldDemo; 197 | sourceTree = SOURCE_ROOT; 198 | }; 199 | /* End PBXGroup section */ 200 | 201 | /* Begin PBXHeadersBuildPhase section */ 202 | 07C541F41D54DD880069498C /* Headers */ = { 203 | isa = PBXHeadersBuildPhase; 204 | buildActionMask = 2147483647; 205 | files = ( 206 | 075E53061D56188C00E56723 /* CustomKeyboardTextField.h in Headers */, 207 | ); 208 | runOnlyForDeploymentPostprocessing = 0; 209 | }; 210 | /* End PBXHeadersBuildPhase section */ 211 | 212 | /* Begin PBXNativeTarget section */ 213 | 07C541F61D54DD880069498C /* CustomKeyboardTextField */ = { 214 | isa = PBXNativeTarget; 215 | buildConfigurationList = 07C5420B1D54DD890069498C /* Build configuration list for PBXNativeTarget "CustomKeyboardTextField" */; 216 | buildPhases = ( 217 | 07C541F21D54DD880069498C /* Sources */, 218 | 07C541F31D54DD880069498C /* Frameworks */, 219 | 07C541F41D54DD880069498C /* Headers */, 220 | 07C541F51D54DD880069498C /* Resources */, 221 | ); 222 | buildRules = ( 223 | ); 224 | dependencies = ( 225 | ); 226 | name = CustomKeyboardTextField; 227 | productName = CustomKeyboardTextField; 228 | productReference = 07C541F71D54DD880069498C /* CustomKeyboardTextField.framework */; 229 | productType = "com.apple.product-type.framework"; 230 | }; 231 | 07C542001D54DD880069498C /* CustomKeyboardTextFieldTests */ = { 232 | isa = PBXNativeTarget; 233 | buildConfigurationList = 07C5420E1D54DD890069498C /* Build configuration list for PBXNativeTarget "CustomKeyboardTextFieldTests" */; 234 | buildPhases = ( 235 | 07C541FD1D54DD880069498C /* Sources */, 236 | 07C541FE1D54DD880069498C /* Frameworks */, 237 | 07C541FF1D54DD880069498C /* Resources */, 238 | ); 239 | buildRules = ( 240 | ); 241 | dependencies = ( 242 | 07C542041D54DD880069498C /* PBXTargetDependency */, 243 | ); 244 | name = CustomKeyboardTextFieldTests; 245 | productName = CustomKeyboardTextFieldTests; 246 | productReference = 07C542011D54DD880069498C /* CustomKeyboardTextFieldTests.xctest */; 247 | productType = "com.apple.product-type.bundle.unit-test"; 248 | }; 249 | 07C5E98E1D54E0720042C657 /* CustomKeyboardTextFieldDemo */ = { 250 | isa = PBXNativeTarget; 251 | buildConfigurationList = 07C5E99E1D54E0720042C657 /* Build configuration list for PBXNativeTarget "CustomKeyboardTextFieldDemo" */; 252 | buildPhases = ( 253 | 07C5E98B1D54E0720042C657 /* Sources */, 254 | 07C5E98C1D54E0720042C657 /* Frameworks */, 255 | 07C5E98D1D54E0720042C657 /* Resources */, 256 | 075E53131D562C5900E56723 /* Embed Frameworks */, 257 | ); 258 | buildRules = ( 259 | ); 260 | dependencies = ( 261 | 075E53121D562C5900E56723 /* PBXTargetDependency */, 262 | ); 263 | name = CustomKeyboardTextFieldDemo; 264 | productName = CustomKeyboardTextFieldDemo; 265 | productReference = 07C5E98F1D54E0720042C657 /* CustomKeyboardTextFieldDemo.app */; 266 | productType = "com.apple.product-type.application"; 267 | }; 268 | /* End PBXNativeTarget section */ 269 | 270 | /* Begin PBXProject section */ 271 | 07C541EE1D54DD880069498C /* Project object */ = { 272 | isa = PBXProject; 273 | attributes = { 274 | LastSwiftUpdateCheck = 0730; 275 | LastUpgradeCheck = 0730; 276 | ORGANIZATIONNAME = giginet; 277 | TargetAttributes = { 278 | 07C541F61D54DD880069498C = { 279 | CreatedOnToolsVersion = 7.3.1; 280 | LastSwiftMigration = 0810; 281 | }; 282 | 07C542001D54DD880069498C = { 283 | CreatedOnToolsVersion = 7.3.1; 284 | LastSwiftMigration = 0810; 285 | }; 286 | 07C5E98E1D54E0720042C657 = { 287 | CreatedOnToolsVersion = 7.3.1; 288 | LastSwiftMigration = 0810; 289 | }; 290 | }; 291 | }; 292 | buildConfigurationList = 07C541F11D54DD880069498C /* Build configuration list for PBXProject "CustomKeyboardTextField" */; 293 | compatibilityVersion = "Xcode 3.2"; 294 | developmentRegion = English; 295 | hasScannedForEncodings = 0; 296 | knownRegions = ( 297 | en, 298 | Base, 299 | ); 300 | mainGroup = 07C541ED1D54DD880069498C; 301 | productRefGroup = 07C541F81D54DD880069498C /* Products */; 302 | projectDirPath = ""; 303 | projectRoot = ""; 304 | targets = ( 305 | 07C541F61D54DD880069498C /* CustomKeyboardTextField */, 306 | 07C542001D54DD880069498C /* CustomKeyboardTextFieldTests */, 307 | 07C5E98E1D54E0720042C657 /* CustomKeyboardTextFieldDemo */, 308 | ); 309 | }; 310 | /* End PBXProject section */ 311 | 312 | /* Begin PBXResourcesBuildPhase section */ 313 | 07C541F51D54DD880069498C /* Resources */ = { 314 | isa = PBXResourcesBuildPhase; 315 | buildActionMask = 2147483647; 316 | files = ( 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | }; 320 | 07C541FF1D54DD880069498C /* Resources */ = { 321 | isa = PBXResourcesBuildPhase; 322 | buildActionMask = 2147483647; 323 | files = ( 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | }; 327 | 07C5E98D1D54E0720042C657 /* Resources */ = { 328 | isa = PBXResourcesBuildPhase; 329 | buildActionMask = 2147483647; 330 | files = ( 331 | 07C5E9B61D54E2790042C657 /* Main.storyboard in Resources */, 332 | 073F47581D55FC6F00865351 /* Squirtle.png in Resources */, 333 | 073F47561D55FC6F00865351 /* Bulbasaur.png in Resources */, 334 | 073F47571D55FC6F00865351 /* Charmander.png in Resources */, 335 | 07C5E9B41D54E2790042C657 /* Assets.xcassets in Resources */, 336 | 07C5E9B51D54E2790042C657 /* LaunchScreen.storyboard in Resources */, 337 | 07BA1CBD1D55BFAA00BB2E85 /* GamePadKeyboardView.xib in Resources */, 338 | ); 339 | runOnlyForDeploymentPostprocessing = 0; 340 | }; 341 | /* End PBXResourcesBuildPhase section */ 342 | 343 | /* Begin PBXSourcesBuildPhase section */ 344 | 07C541F21D54DD880069498C /* Sources */ = { 345 | isa = PBXSourcesBuildPhase; 346 | buildActionMask = 2147483647; 347 | files = ( 348 | 075E530A1D56188C00E56723 /* UIDatePickerKeyboard.swift in Sources */, 349 | 075E53091D56188C00E56723 /* ToolbarAccessoryView.swift in Sources */, 350 | 075E53081D56188C00E56723 /* CustomKeyboardProvider.swift in Sources */, 351 | 075E53071D56188C00E56723 /* CustomKeyboardTextField.swift in Sources */, 352 | 075E530B1D56188C00E56723 /* UIPickerViewKeyboard.swift in Sources */, 353 | ); 354 | runOnlyForDeploymentPostprocessing = 0; 355 | }; 356 | 07C541FD1D54DD880069498C /* Sources */ = { 357 | isa = PBXSourcesBuildPhase; 358 | buildActionMask = 2147483647; 359 | files = ( 360 | 075E530E1D561C9D00E56723 /* UIDatePickerKeyboardTests.swift in Sources */, 361 | 075E52FD1D56187800E56723 /* UIPickerViewKeyboardTests.swift in Sources */, 362 | ); 363 | runOnlyForDeploymentPostprocessing = 0; 364 | }; 365 | 07C5E98B1D54E0720042C657 /* Sources */ = { 366 | isa = PBXSourcesBuildPhase; 367 | buildActionMask = 2147483647; 368 | files = ( 369 | 07BA1CBB1D55BF8A00BB2E85 /* CustomKeyboard.swift in Sources */, 370 | 07C5E9B81D54E2790042C657 /* ViewController.swift in Sources */, 371 | 07C5E9B31D54E2790042C657 /* AppDelegate.swift in Sources */, 372 | ); 373 | runOnlyForDeploymentPostprocessing = 0; 374 | }; 375 | /* End PBXSourcesBuildPhase section */ 376 | 377 | /* Begin PBXTargetDependency section */ 378 | 075E53121D562C5900E56723 /* PBXTargetDependency */ = { 379 | isa = PBXTargetDependency; 380 | target = 07C541F61D54DD880069498C /* CustomKeyboardTextField */; 381 | targetProxy = 075E53111D562C5900E56723 /* PBXContainerItemProxy */; 382 | }; 383 | 07C542041D54DD880069498C /* PBXTargetDependency */ = { 384 | isa = PBXTargetDependency; 385 | target = 07C541F61D54DD880069498C /* CustomKeyboardTextField */; 386 | targetProxy = 07C542031D54DD880069498C /* PBXContainerItemProxy */; 387 | }; 388 | /* End PBXTargetDependency section */ 389 | 390 | /* Begin PBXVariantGroup section */ 391 | 07C5E9AD1D54E2790042C657 /* LaunchScreen.storyboard */ = { 392 | isa = PBXVariantGroup; 393 | children = ( 394 | 07C5E9AE1D54E2790042C657 /* Base */, 395 | ); 396 | name = LaunchScreen.storyboard; 397 | sourceTree = ""; 398 | }; 399 | 07C5E9AF1D54E2790042C657 /* Main.storyboard */ = { 400 | isa = PBXVariantGroup; 401 | children = ( 402 | 07C5E9B01D54E2790042C657 /* Base */, 403 | ); 404 | name = Main.storyboard; 405 | sourceTree = ""; 406 | }; 407 | /* End PBXVariantGroup section */ 408 | 409 | /* Begin XCBuildConfiguration section */ 410 | 07C542091D54DD890069498C /* Debug */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | ALWAYS_SEARCH_USER_PATHS = NO; 414 | CLANG_ANALYZER_NONNULL = YES; 415 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 416 | CLANG_CXX_LIBRARY = "libc++"; 417 | CLANG_ENABLE_MODULES = YES; 418 | CLANG_ENABLE_OBJC_ARC = YES; 419 | CLANG_WARN_BOOL_CONVERSION = YES; 420 | CLANG_WARN_CONSTANT_CONVERSION = YES; 421 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 422 | CLANG_WARN_EMPTY_BODY = YES; 423 | CLANG_WARN_ENUM_CONVERSION = YES; 424 | CLANG_WARN_INT_CONVERSION = YES; 425 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 426 | CLANG_WARN_UNREACHABLE_CODE = YES; 427 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 428 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 429 | COPY_PHASE_STRIP = NO; 430 | CURRENT_PROJECT_VERSION = 1; 431 | DEBUG_INFORMATION_FORMAT = dwarf; 432 | ENABLE_STRICT_OBJC_MSGSEND = YES; 433 | ENABLE_TESTABILITY = YES; 434 | GCC_C_LANGUAGE_STANDARD = gnu99; 435 | GCC_DYNAMIC_NO_PIC = NO; 436 | GCC_NO_COMMON_BLOCKS = YES; 437 | GCC_OPTIMIZATION_LEVEL = 0; 438 | GCC_PREPROCESSOR_DEFINITIONS = ( 439 | "DEBUG=1", 440 | "$(inherited)", 441 | ); 442 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 443 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 444 | GCC_WARN_UNDECLARED_SELECTOR = YES; 445 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 446 | GCC_WARN_UNUSED_FUNCTION = YES; 447 | GCC_WARN_UNUSED_VARIABLE = YES; 448 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 449 | MTL_ENABLE_DEBUG_INFO = YES; 450 | ONLY_ACTIVE_ARCH = YES; 451 | SDKROOT = iphoneos; 452 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 453 | TARGETED_DEVICE_FAMILY = "1,2"; 454 | VERSIONING_SYSTEM = "apple-generic"; 455 | VERSION_INFO_PREFIX = ""; 456 | }; 457 | name = Debug; 458 | }; 459 | 07C5420A1D54DD890069498C /* Release */ = { 460 | isa = XCBuildConfiguration; 461 | buildSettings = { 462 | ALWAYS_SEARCH_USER_PATHS = NO; 463 | CLANG_ANALYZER_NONNULL = YES; 464 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 465 | CLANG_CXX_LIBRARY = "libc++"; 466 | CLANG_ENABLE_MODULES = YES; 467 | CLANG_ENABLE_OBJC_ARC = YES; 468 | CLANG_WARN_BOOL_CONVERSION = YES; 469 | CLANG_WARN_CONSTANT_CONVERSION = YES; 470 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 471 | CLANG_WARN_EMPTY_BODY = YES; 472 | CLANG_WARN_ENUM_CONVERSION = YES; 473 | CLANG_WARN_INT_CONVERSION = YES; 474 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 475 | CLANG_WARN_UNREACHABLE_CODE = YES; 476 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 477 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 478 | COPY_PHASE_STRIP = NO; 479 | CURRENT_PROJECT_VERSION = 1; 480 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 481 | ENABLE_NS_ASSERTIONS = NO; 482 | ENABLE_STRICT_OBJC_MSGSEND = YES; 483 | GCC_C_LANGUAGE_STANDARD = gnu99; 484 | GCC_NO_COMMON_BLOCKS = YES; 485 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 486 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 487 | GCC_WARN_UNDECLARED_SELECTOR = YES; 488 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 489 | GCC_WARN_UNUSED_FUNCTION = YES; 490 | GCC_WARN_UNUSED_VARIABLE = YES; 491 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 492 | MTL_ENABLE_DEBUG_INFO = NO; 493 | SDKROOT = iphoneos; 494 | TARGETED_DEVICE_FAMILY = "1,2"; 495 | VALIDATE_PRODUCT = YES; 496 | VERSIONING_SYSTEM = "apple-generic"; 497 | VERSION_INFO_PREFIX = ""; 498 | }; 499 | name = Release; 500 | }; 501 | 07C5420C1D54DD890069498C /* Debug */ = { 502 | isa = XCBuildConfiguration; 503 | buildSettings = { 504 | CLANG_ENABLE_MODULES = YES; 505 | DEFINES_MODULE = YES; 506 | DYLIB_COMPATIBILITY_VERSION = 1; 507 | DYLIB_CURRENT_VERSION = 1; 508 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 509 | INFOPLIST_FILE = Sources/Info.plist; 510 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 511 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 512 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 513 | PRODUCT_BUNDLE_IDENTIFIER = org.giginet.CustomKeyboardTextField; 514 | PRODUCT_NAME = "$(TARGET_NAME)"; 515 | SKIP_INSTALL = YES; 516 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 517 | SWIFT_VERSION = 3.0; 518 | }; 519 | name = Debug; 520 | }; 521 | 07C5420D1D54DD890069498C /* Release */ = { 522 | isa = XCBuildConfiguration; 523 | buildSettings = { 524 | CLANG_ENABLE_MODULES = YES; 525 | DEFINES_MODULE = YES; 526 | DYLIB_COMPATIBILITY_VERSION = 1; 527 | DYLIB_CURRENT_VERSION = 1; 528 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 529 | INFOPLIST_FILE = Sources/Info.plist; 530 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 531 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 532 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 533 | PRODUCT_BUNDLE_IDENTIFIER = org.giginet.CustomKeyboardTextField; 534 | PRODUCT_NAME = "$(TARGET_NAME)"; 535 | SKIP_INSTALL = YES; 536 | SWIFT_VERSION = 3.0; 537 | }; 538 | name = Release; 539 | }; 540 | 07C5420F1D54DD890069498C /* Debug */ = { 541 | isa = XCBuildConfiguration; 542 | buildSettings = { 543 | CLANG_ENABLE_MODULES = YES; 544 | INFOPLIST_FILE = Tests/CustomKeyboardTextField/Info.plist; 545 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 546 | PRODUCT_BUNDLE_IDENTIFIER = org.giginet.CustomKeyboardTextFieldTests; 547 | PRODUCT_NAME = "$(TARGET_NAME)"; 548 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 549 | SWIFT_VERSION = 3.0; 550 | }; 551 | name = Debug; 552 | }; 553 | 07C542101D54DD890069498C /* Release */ = { 554 | isa = XCBuildConfiguration; 555 | buildSettings = { 556 | CLANG_ENABLE_MODULES = YES; 557 | INFOPLIST_FILE = Tests/CustomKeyboardTextField/Info.plist; 558 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 559 | PRODUCT_BUNDLE_IDENTIFIER = org.giginet.CustomKeyboardTextFieldTests; 560 | PRODUCT_NAME = "$(TARGET_NAME)"; 561 | SWIFT_VERSION = 3.0; 562 | }; 563 | name = Release; 564 | }; 565 | 07C5E99F1D54E0720042C657 /* Debug */ = { 566 | isa = XCBuildConfiguration; 567 | buildSettings = { 568 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 569 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 570 | INFOPLIST_FILE = CustomKeyboardTextFieldDemo/Info.plist; 571 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 572 | PRODUCT_BUNDLE_IDENTIFIER = org.giginet.CustomKeyboardTextFieldDemo; 573 | PRODUCT_NAME = "$(TARGET_NAME)"; 574 | SWIFT_VERSION = 3.0; 575 | }; 576 | name = Debug; 577 | }; 578 | 07C5E9A01D54E0720042C657 /* Release */ = { 579 | isa = XCBuildConfiguration; 580 | buildSettings = { 581 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 582 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 583 | INFOPLIST_FILE = CustomKeyboardTextFieldDemo/Info.plist; 584 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 585 | PRODUCT_BUNDLE_IDENTIFIER = org.giginet.CustomKeyboardTextFieldDemo; 586 | PRODUCT_NAME = "$(TARGET_NAME)"; 587 | SWIFT_VERSION = 3.0; 588 | }; 589 | name = Release; 590 | }; 591 | /* End XCBuildConfiguration section */ 592 | 593 | /* Begin XCConfigurationList section */ 594 | 07C541F11D54DD880069498C /* Build configuration list for PBXProject "CustomKeyboardTextField" */ = { 595 | isa = XCConfigurationList; 596 | buildConfigurations = ( 597 | 07C542091D54DD890069498C /* Debug */, 598 | 07C5420A1D54DD890069498C /* Release */, 599 | ); 600 | defaultConfigurationIsVisible = 0; 601 | defaultConfigurationName = Release; 602 | }; 603 | 07C5420B1D54DD890069498C /* Build configuration list for PBXNativeTarget "CustomKeyboardTextField" */ = { 604 | isa = XCConfigurationList; 605 | buildConfigurations = ( 606 | 07C5420C1D54DD890069498C /* Debug */, 607 | 07C5420D1D54DD890069498C /* Release */, 608 | ); 609 | defaultConfigurationIsVisible = 0; 610 | defaultConfigurationName = Release; 611 | }; 612 | 07C5420E1D54DD890069498C /* Build configuration list for PBXNativeTarget "CustomKeyboardTextFieldTests" */ = { 613 | isa = XCConfigurationList; 614 | buildConfigurations = ( 615 | 07C5420F1D54DD890069498C /* Debug */, 616 | 07C542101D54DD890069498C /* Release */, 617 | ); 618 | defaultConfigurationIsVisible = 0; 619 | defaultConfigurationName = Release; 620 | }; 621 | 07C5E99E1D54E0720042C657 /* Build configuration list for PBXNativeTarget "CustomKeyboardTextFieldDemo" */ = { 622 | isa = XCConfigurationList; 623 | buildConfigurations = ( 624 | 07C5E99F1D54E0720042C657 /* Debug */, 625 | 07C5E9A01D54E0720042C657 /* Release */, 626 | ); 627 | defaultConfigurationIsVisible = 0; 628 | defaultConfigurationName = Release; 629 | }; 630 | /* End XCConfigurationList section */ 631 | }; 632 | rootObject = 07C541EE1D54DD880069498C /* Project object */; 633 | } 634 | -------------------------------------------------------------------------------- /CustomKeyboardTextField.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CustomKeyboardTextField.xcodeproj/xcshareddata/xcschemes/CustomKeyboardTextField.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /CustomKeyboardTextField.xcodeproj/xcshareddata/xcschemes/CustomKeyboardTextFieldDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /CustomKeyboardTextField.xcodeproj/xcshareddata/xcschemes/CustomKeyboardTextFieldTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 16 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 40 | 41 | 42 | 43 | 49 | 50 | 52 | 53 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /CustomKeyboardTextFieldDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | 6 | var window: UIWindow? 7 | 8 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 9 | // Override point for customization after application launch. 10 | return true 11 | } 12 | 13 | func applicationWillResignActive(_ application: UIApplication) { 14 | // 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. 15 | // 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. 16 | } 17 | 18 | func applicationDidEnterBackground(_ application: UIApplication) { 19 | // 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. 20 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 21 | } 22 | 23 | func applicationWillEnterForeground(_ application: UIApplication) { 24 | // 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. 25 | } 26 | 27 | func applicationDidBecomeActive(_ application: UIApplication) { 28 | // 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. 29 | } 30 | 31 | func applicationWillTerminate(_ application: UIApplication) { 32 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /CustomKeyboardTextFieldDemo/Assets.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 | } -------------------------------------------------------------------------------- /CustomKeyboardTextFieldDemo/Base.lproj/LaunchScreen.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 | -------------------------------------------------------------------------------- /CustomKeyboardTextFieldDemo/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 | -------------------------------------------------------------------------------- /CustomKeyboardTextFieldDemo/CustomKeyboard.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import CustomKeyboardTextField 3 | 4 | // MARK - Pokemon PickerView Keyboard 5 | 6 | struct PokemonPickerKeyboardDataSource: UIPickerViewKeyboardDataSource { 7 | let elements = ["Bulbasaur", "Charmander", "Squirtle"] 8 | } 9 | 10 | class PokemonPickerKeyboard: UIPickerViewKeyboard { 11 | let rowHeight: CGFloat = 44.0 12 | 13 | required init(with textField: UITextField, pickerKeyboardViewDataSource: PokemonPickerKeyboardDataSource) { 14 | super.init(with: textField, pickerKeyboardViewDataSource: pickerKeyboardViewDataSource) 15 | } 16 | 17 | required init?(coder aDecoder: NSCoder) { 18 | fatalError("init(coder:) has not been implemented") 19 | } 20 | 21 | func pickerView(_ picker: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView { 22 | if let view = view { 23 | return view 24 | } 25 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: rowHeight)) 26 | view.addSubview(iconView(row)) 27 | 28 | return view 29 | } 30 | 31 | func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { 32 | return rowHeight 33 | } 34 | 35 | private func iconView(_ row: Int) -> UIImageView { 36 | let pokemonName = pickerView(self, titleForRow: row, forComponent: 0)! 37 | let image = UIImage(named: "\(pokemonName).png") 38 | return UIImageView(image: image) 39 | } 40 | 41 | private func updateTextField(for row: Int) { 42 | textField?.text = pickerKeyboardDataSource.elements[row] 43 | textField?.leftViewMode = .always 44 | textField?.leftView = iconView(row) 45 | } 46 | 47 | override func updateTextField() { 48 | updateTextField(for: selectedRow(inComponent: 0)) 49 | } 50 | } 51 | 52 | struct PokemonPickerKeyboardProvider: CustomKeyboardProvider { 53 | let dataSource = PokemonPickerKeyboardDataSource() 54 | 55 | func inputView(with textField: UITextField) -> CustomKeyboardView? { 56 | let picker = PokemonPickerKeyboard(with: textField, pickerKeyboardViewDataSource: dataSource) 57 | return picker 58 | } 59 | } 60 | 61 | typealias PokemonPickerKeyboardTextField = CustomKeyboardTextField 62 | 63 | // MARK - GamePad Keyboard 64 | 65 | class GamePadKeyboardView: UIView, CustomKeyboardView { 66 | weak var textField: UITextField? 67 | var inputText: String? = "" 68 | 69 | @IBOutlet weak var aButton: UIButton! 70 | @IBOutlet weak var bButton: UIButton! 71 | @IBOutlet weak var startButton: UIButton! 72 | @IBOutlet weak var selectButton: UIButton! 73 | @IBOutlet weak var upButton: UIButton! 74 | @IBOutlet weak var rightButton: UIButton! 75 | @IBOutlet weak var downButton: UIButton! 76 | @IBOutlet weak var leftButton: UIButton! 77 | 78 | override func awakeFromNib() { 79 | super.awakeFromNib() 80 | 81 | let buttons = [ 82 | aButton, 83 | bButton, 84 | startButton, 85 | selectButton, 86 | upButton, 87 | rightButton, 88 | downButton, 89 | leftButton 90 | ] 91 | 92 | for button in buttons { 93 | button?.addTarget(self, action: #selector(buttonDidTap(_:)), for: .touchUpInside) 94 | } 95 | } 96 | 97 | func buttonDidTap(_ sender: UIButton) { 98 | switch sender { 99 | case aButton: insertText("A") 100 | case bButton: insertText("B") 101 | case startButton: insertText("START") 102 | case selectButton: insertText("SELECT") 103 | case upButton: insertText("⬆️") 104 | case rightButton: insertText("➡️") 105 | case downButton: insertText("⬇️") 106 | case leftButton: insertText("⬅️") 107 | default: break 108 | } 109 | } 110 | 111 | private func insertText(_ insertText: String) { 112 | if let text = textField?.text { 113 | inputText = "\(text) \(insertText)" 114 | } 115 | updateTextField() 116 | } 117 | 118 | func reset() { 119 | inputText = nil 120 | } 121 | } 122 | 123 | struct GamePadKeyboardProvider: CustomKeyboardProvider { 124 | weak var textField: UITextField! 125 | 126 | func inputView(with textField: UITextField) -> CustomKeyboardView? { 127 | let gamePadNib = UINib(nibName: "GamePadKeyboardView", bundle: nil) 128 | if let gamePad = gamePadNib.instantiate(withOwner: nil, options: nil).first as? GamePadKeyboardView { 129 | gamePad.textField = textField 130 | return gamePad 131 | } 132 | return nil 133 | } 134 | } 135 | 136 | typealias GamePadKeyboardTextField = CustomKeyboardTextField 137 | -------------------------------------------------------------------------------- /CustomKeyboardTextFieldDemo/GamePadKeyboardView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 22 | 26 | 30 | 34 | 38 | 42 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /CustomKeyboardTextFieldDemo/Images/Bulbasaur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/c651e409f2e20069b320a54cf5d915b994898a8e/CustomKeyboardTextFieldDemo/Images/Bulbasaur.png -------------------------------------------------------------------------------- /CustomKeyboardTextFieldDemo/Images/Charmander.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/c651e409f2e20069b320a54cf5d915b994898a8e/CustomKeyboardTextFieldDemo/Images/Charmander.png -------------------------------------------------------------------------------- /CustomKeyboardTextFieldDemo/Images/Squirtle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/c651e409f2e20069b320a54cf5d915b994898a8e/CustomKeyboardTextFieldDemo/Images/Squirtle.png -------------------------------------------------------------------------------- /CustomKeyboardTextFieldDemo/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 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /CustomKeyboardTextFieldDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import CustomKeyboardTextField 3 | 4 | struct SimplePickerKeyboardDataSource: UIPickerViewKeyboardDataSource { 5 | let elements = ["Bulbasaur", "Charmander", "Squirtle"] 6 | } 7 | 8 | typealias SimplePickerTextField = PickerKeyboardTextField 9 | 10 | struct GenderPickerKeyboardDataSource: UIPickerViewKeyboardDataSource { 11 | let elements = ["Unknown", "Female", "Male"] 12 | 13 | func inputText(for row: Int) -> String? { 14 | if row == 0 { 15 | return nil 16 | } 17 | return elements[row] 18 | } 19 | } 20 | 21 | typealias GenderPickerTextField = PickerKeyboardTextField 22 | 23 | struct DateTimePickerKeyboardDataSource: UIDatePickerKeyboardDataSource { } 24 | 25 | typealias DateTimePickerTextField = UIDatePickerKeyboardTextField 26 | 27 | struct DatePickerKeyboardDataSource: UIDatePickerKeyboardDataSource { 28 | let datePickerMode: UIDatePickerMode = .date 29 | let timeFormat: String = "yyyy/MM/dd" 30 | } 31 | 32 | typealias DatePickerTextField = UIDatePickerKeyboardTextField 33 | 34 | class ViewController: UIViewController { 35 | override func awakeFromNib() { 36 | super.awakeFromNib() 37 | 38 | let pickerTextField = SimplePickerTextField() 39 | pickerTextField.placeholder = "Picker" 40 | 41 | let genderPickerTextField = GenderPickerTextField() 42 | genderPickerTextField.placeholder = "Gender" 43 | 44 | let pokemonPickerTextField = PokemonPickerKeyboardTextField() 45 | pokemonPickerTextField.placeholder = "Rich Picker" 46 | 47 | let dateTimePickerTextField = DateTimePickerTextField() 48 | dateTimePickerTextField.placeholder = "Date Time Picker" 49 | 50 | let datePickerTextField = DatePickerTextField() 51 | datePickerTextField.placeholder = "Date Picker" 52 | 53 | let gamePadTextField = GamePadKeyboardTextField() 54 | gamePadTextField.placeholder = "Game Pad" 55 | 56 | view.translatesAutoresizingMaskIntoConstraints = false 57 | 58 | let textFields = [ 59 | pickerTextField, 60 | genderPickerTextField, 61 | pokemonPickerTextField, 62 | dateTimePickerTextField, 63 | datePickerTextField, 64 | gamePadTextField 65 | ] 66 | 67 | for (index, textField) in textFields.enumerated() { 68 | textField.backgroundColor = UIColor.white 69 | view.addSubview(textField) 70 | 71 | textField.translatesAutoresizingMaskIntoConstraints = false 72 | 73 | let topConstraints: NSLayoutConstraint 74 | if index == 0 { 75 | topConstraints = NSLayoutConstraint(item: textField, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1.0, constant: 40) 76 | } else { 77 | let previousField = textFields[index - 1] 78 | topConstraints = NSLayoutConstraint(item: textField, attribute: .top, relatedBy: .equal, toItem: previousField, attribute: .top, multiplier: 1.0, constant: 40) 79 | } 80 | 81 | pickerTextField.translatesAutoresizingMaskIntoConstraints = false 82 | view.addConstraints([ 83 | NSLayoutConstraint(item: textField, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1.0, constant: 32), 84 | topConstraints, 85 | NSLayoutConstraint(item: textField, attribute: .leadingMargin, relatedBy: .equal, toItem: view, attribute: .leadingMargin, multiplier: 1.0, constant: 8), 86 | NSLayoutConstraint(item: textField, attribute: .trailingMargin, relatedBy: .equal, toItem: view, attribute: .trailingMargin, multiplier: 1.0, constant: -8) 87 | ]) 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Documentation/Image/custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/c651e409f2e20069b320a54cf5d915b994898a8e/Documentation/Image/custom.png -------------------------------------------------------------------------------- /Documentation/Image/date_picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/c651e409f2e20069b320a54cf5d915b994898a8e/Documentation/Image/date_picker.png -------------------------------------------------------------------------------- /Documentation/Image/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/c651e409f2e20069b320a54cf5d915b994898a8e/Documentation/Image/demo.gif -------------------------------------------------------------------------------- /Documentation/Image/picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/c651e409f2e20069b320a54cf5d915b994898a8e/Documentation/Image/picker.png -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "cocoapods", "~> 1.1" 4 | gem "fastlane" 5 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (2.3.4) 5 | activesupport (4.2.7.1) 6 | i18n (~> 0.7) 7 | json (~> 1.7, >= 1.7.7) 8 | minitest (~> 5.1) 9 | thread_safe (~> 0.3, >= 0.3.4) 10 | tzinfo (~> 1.1) 11 | addressable (2.5.0) 12 | public_suffix (~> 2.0, >= 2.0.2) 13 | babosa (1.0.2) 14 | cert (1.4.4) 15 | fastlane_core (>= 0.55.0, < 1.0.0) 16 | spaceship (>= 0.37.0, < 1.0.0) 17 | claide (1.0.1) 18 | cocoapods (1.1.1) 19 | activesupport (>= 4.0.2, < 5) 20 | claide (>= 1.0.1, < 2.0) 21 | cocoapods-core (= 1.1.1) 22 | cocoapods-deintegrate (>= 1.0.1, < 2.0) 23 | cocoapods-downloader (>= 1.1.2, < 2.0) 24 | cocoapods-plugins (>= 1.0.0, < 2.0) 25 | cocoapods-search (>= 1.0.0, < 2.0) 26 | cocoapods-stats (>= 1.0.0, < 2.0) 27 | cocoapods-trunk (>= 1.1.1, < 2.0) 28 | cocoapods-try (>= 1.1.0, < 2.0) 29 | colored (~> 1.2) 30 | escape (~> 0.0.4) 31 | fourflusher (~> 2.0.1) 32 | gh_inspector (~> 1.0) 33 | molinillo (~> 0.5.1) 34 | nap (~> 1.0) 35 | xcodeproj (>= 1.3.3, < 2.0) 36 | cocoapods-core (1.1.1) 37 | activesupport (>= 4.0.2, < 5) 38 | fuzzy_match (~> 2.0.4) 39 | nap (~> 1.0) 40 | cocoapods-deintegrate (1.0.1) 41 | cocoapods-downloader (1.1.2) 42 | cocoapods-plugins (1.0.0) 43 | nap 44 | cocoapods-search (1.0.0) 45 | cocoapods-stats (1.0.0) 46 | cocoapods-trunk (1.1.1) 47 | nap (>= 0.8, < 2.0) 48 | netrc (= 0.7.8) 49 | cocoapods-try (1.1.0) 50 | colored (1.2) 51 | commander (4.4.1) 52 | highline (~> 1.7.2) 53 | credentials_manager (0.16.2) 54 | colored 55 | commander (>= 4.3.5) 56 | highline (>= 1.7.1) 57 | security 58 | deliver (1.16.1) 59 | credentials_manager (>= 0.16.2, < 1.0.0) 60 | fastimage (~> 1.6) 61 | fastlane_core (>= 0.58.0, < 1.0.0) 62 | plist (>= 3.1.0, < 4.0.0) 63 | spaceship (>= 0.38.5, < 1.0.0) 64 | domain_name (0.5.20161129) 65 | unf (>= 0.0.5, < 1.0.0) 66 | dotenv (2.1.1) 67 | escape (0.0.4) 68 | excon (0.54.0) 69 | faraday (0.10.0) 70 | multipart-post (>= 1.2, < 3) 71 | faraday-cookie_jar (0.0.6) 72 | faraday (>= 0.7.4) 73 | http-cookie (~> 1.0.0) 74 | faraday_middleware (0.10.1) 75 | faraday (>= 0.7.4, < 1.0) 76 | fastimage (1.6.8) 77 | addressable (~> 2.3, >= 2.3.5) 78 | fastlane (1.111.0) 79 | activesupport (< 5) 80 | addressable (>= 2.3, < 3.0.0) 81 | bundler (~> 1.12) 82 | cert (>= 1.4.4, < 2.0.0) 83 | credentials_manager (>= 0.16.2, < 1.0.0) 84 | deliver (>= 1.15.1, < 2.0.0) 85 | fastlane_core (>= 0.57.1, < 1.0.0) 86 | frameit (>= 3.0.0, < 4.0.0) 87 | gym (>= 1.12.1, < 2.0.0) 88 | krausefx-shenzhen (>= 0.14.11, < 1.0.0) 89 | match (>= 0.11.0, < 1.0.0) 90 | multipart-post (~> 2.0.0) 91 | pem (>= 1.4.0, < 2.0.0) 92 | pilot (>= 1.12.1, < 2.0.0) 93 | plist (>= 3.1.0, < 4.0.0) 94 | produce (>= 1.3.1, < 2.0.0) 95 | scan (>= 0.14.2, < 1.0.0) 96 | screengrab (>= 0.5.2, < 1.0.0) 97 | sigh (>= 1.11.2, < 2.0.0) 98 | slack-notifier (>= 1.3, < 2.0.0) 99 | snapshot (>= 1.16.4, < 2.0.0) 100 | spaceship (>= 0.38.1, < 1.0.0) 101 | supply (>= 0.8.0, < 1.0.0) 102 | terminal-notifier (>= 1.6.2, < 2.0.0) 103 | terminal-table (>= 1.4.5, < 2.0.0) 104 | word_wrap (~> 1.0.0) 105 | xcode-install (~> 2.0.0) 106 | xcodeproj (>= 0.20, < 2.0.0) 107 | xcpretty (>= 0.2.4, < 1.0.0) 108 | fastlane_core (0.59.0) 109 | colored 110 | commander (>= 4.4.0, <= 5.0.0) 111 | credentials_manager (>= 0.16.2, < 1.0.0) 112 | excon (>= 0.45.0, < 1.0) 113 | gh_inspector (>= 1.0.1, < 2.0.0) 114 | highline (>= 1.7.2) 115 | json 116 | multi_json 117 | plist (>= 3.1.0, < 4.0.0) 118 | rubyzip (~> 1.1.6) 119 | terminal-table (>= 1.4.5, < 2.0.0) 120 | fourflusher (2.0.1) 121 | frameit (3.0.0) 122 | deliver (> 0.3) 123 | fastimage (~> 1.6.3) 124 | fastlane_core (>= 0.53.0, < 1.0.0) 125 | mini_magick (~> 4.5.1) 126 | fuzzy_match (2.0.4) 127 | gh_inspector (1.0.2) 128 | google-api-client (0.9.20) 129 | addressable (~> 2.3) 130 | googleauth (~> 0.5) 131 | httpclient (~> 2.7) 132 | hurley (~> 0.1) 133 | memoist (~> 0.11) 134 | mime-types (>= 1.6) 135 | representable (~> 2.3.0) 136 | retriable (~> 2.0) 137 | googleauth (0.5.1) 138 | faraday (~> 0.9) 139 | jwt (~> 1.4) 140 | logging (~> 2.0) 141 | memoist (~> 0.12) 142 | multi_json (~> 1.11) 143 | os (~> 0.9) 144 | signet (~> 0.7) 145 | gym (1.12.1) 146 | fastlane_core (>= 0.57.0, < 1.0.0) 147 | plist (>= 3.1.0, < 4.0.0) 148 | rubyzip (>= 1.1.7) 149 | terminal-table (>= 1.4.5, < 2.0.0) 150 | xcpretty (>= 0.2.4, < 1.0.0) 151 | highline (1.7.8) 152 | http-cookie (1.0.3) 153 | domain_name (~> 0.5) 154 | httpclient (2.8.3) 155 | hurley (0.2) 156 | i18n (0.7.0) 157 | json (1.8.3) 158 | jwt (1.5.6) 159 | krausefx-shenzhen (0.14.11) 160 | commander (>= 4.3, < 5.0) 161 | dotenv (>= 0.7) 162 | faraday (~> 0.9) 163 | faraday_middleware (~> 0.9) 164 | highline (>= 1.7.2) 165 | json (~> 1.8) 166 | net-sftp (~> 2.1.2) 167 | plist (>= 3.1.0, < 4.0.0) 168 | rubyzip (~> 1.1) 169 | security (~> 0.1.3) 170 | terminal-table (~> 1.4.5) 171 | little-plugger (1.1.4) 172 | logging (2.1.0) 173 | little-plugger (~> 1.1) 174 | multi_json (~> 1.10) 175 | match (0.11.1) 176 | cert (>= 1.4.4, < 2.0.0) 177 | credentials_manager (>= 0.16.2, < 1.0.0) 178 | fastlane_core (>= 0.58.0, < 1.0.0) 179 | security 180 | sigh (>= 1.12.1, < 2.0.0) 181 | spaceship (>= 0.38.5, < 1.0.0) 182 | memoist (0.15.0) 183 | mime-types (3.1) 184 | mime-types-data (~> 3.2015) 185 | mime-types-data (3.2016.0521) 186 | mini_magick (4.5.1) 187 | minitest (5.10.1) 188 | molinillo (0.5.4) 189 | multi_json (1.12.1) 190 | multi_xml (0.6.0) 191 | multipart-post (2.0.0) 192 | nanaimo (0.2.3) 193 | nap (1.1.0) 194 | net-sftp (2.1.2) 195 | net-ssh (>= 2.6.5) 196 | net-ssh (3.2.0) 197 | netrc (0.7.8) 198 | os (0.9.6) 199 | pem (1.4.1) 200 | fastlane_core (>= 0.58.0, < 1.0.0) 201 | spaceship (>= 0.38.5, < 1.0.0) 202 | pilot (1.12.1) 203 | credentials_manager (>= 0.16.0) 204 | fastlane_core (>= 0.56.0, < 1.0.0) 205 | spaceship (>= 0.37.0, < 1.0.0) 206 | terminal-table (>= 1.4.5, < 2.0.0) 207 | plist (3.2.0) 208 | produce (1.3.2) 209 | fastlane_core (>= 0.57.2, < 1.0.0) 210 | spaceship (>= 0.38.4, < 1.0.0) 211 | public_suffix (2.0.4) 212 | representable (2.3.0) 213 | uber (~> 0.0.7) 214 | retriable (2.1.0) 215 | rouge (1.11.1) 216 | rubyzip (1.1.7) 217 | scan (0.14.2) 218 | fastlane_core (>= 0.57.0, < 1.0.0) 219 | slack-notifier (~> 1.3) 220 | terminal-table (>= 1.4.5, < 2.0.0) 221 | xcpretty (>= 0.2.4, < 1.0.0) 222 | xcpretty-travis-formatter (>= 0.0.3) 223 | screengrab (0.5.6) 224 | fastlane_core (>= 0.55.0, < 1.0.0) 225 | security (0.1.3) 226 | sigh (1.12.1) 227 | fastlane_core (>= 0.57.2, < 1.0.0) 228 | plist (>= 3.1.0, < 4.0.0) 229 | spaceship (>= 0.38.4, < 1.0.0) 230 | signet (0.7.3) 231 | addressable (~> 2.3) 232 | faraday (~> 0.9) 233 | jwt (~> 1.5) 234 | multi_json (~> 1.10) 235 | slack-notifier (1.5.1) 236 | snapshot (1.16.4) 237 | fastimage (~> 1.6.3) 238 | fastlane_core (>= 0.57.0, < 1.0.0) 239 | plist (>= 3.1.0, < 4.0.0) 240 | xcpretty (>= 0.2.4, < 1.0.0) 241 | spaceship (0.38.5) 242 | babosa (= 1.0.2) 243 | colored 244 | credentials_manager (>= 0.16.0) 245 | faraday (~> 0.9) 246 | faraday-cookie_jar (~> 0.0.6) 247 | faraday_middleware (~> 0.9) 248 | fastimage (~> 1.6) 249 | multi_xml (~> 0.5) 250 | plist (>= 3.1.0, < 4.0.0) 251 | supply (0.8.0) 252 | credentials_manager (>= 0.16.0) 253 | fastlane_core (>= 0.52.0) 254 | google-api-client (~> 0.9.1) 255 | terminal-notifier (1.7.1) 256 | terminal-table (1.4.5) 257 | thread_safe (0.3.5) 258 | tzinfo (1.2.2) 259 | thread_safe (~> 0.1) 260 | uber (0.0.15) 261 | unf (0.1.4) 262 | unf_ext 263 | unf_ext (0.0.7.2) 264 | word_wrap (1.0.0) 265 | xcode-install (2.0.9) 266 | claide (>= 0.9.1, < 1.1.0) 267 | spaceship (>= 0.25.1, < 1.0.0) 268 | xcodeproj (1.4.1) 269 | CFPropertyList (~> 2.3.3) 270 | activesupport (>= 3) 271 | claide (>= 1.0.1, < 2.0) 272 | colored (~> 1.2) 273 | nanaimo (~> 0.2.0) 274 | xcpretty (0.2.4) 275 | rouge (~> 1.8) 276 | xcpretty-travis-formatter (0.0.4) 277 | xcpretty (~> 0.2, >= 0.0.7) 278 | 279 | PLATFORMS 280 | ruby 281 | 282 | DEPENDENCIES 283 | cocoapods (~> 1.1) 284 | fastlane 285 | 286 | BUNDLED WITH 287 | 1.12.5 288 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Kohki Miki 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CustomKeyboardTextField 2 | 3 | [![Build Status](https://travis-ci.org/giginet/CustomKeyboardTextField.svg?branch=master)](https://travis-ci.org/giginet/CustomKeyboardTextField) 4 | [![codecov](https://codecov.io/gh/giginet/CustomKeyboardTextField/branch/master/graph/badge.svg)](https://codecov.io/gh/giginet/CustomKeyboardTextField) 5 | [![Language](https://img.shields.io/badge/language-Swift%203.0-orange.svg)](https://swift.org) 6 | [![Platform](https://img.shields.io/cocoapods/p/CustomKeyboardTextField.svg?style=flat)](http://cocoadocs.org/docsets/CustomKeyboardTextField) 7 | [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/CustomKeyboardTextField.svg)](https://img.shields.io/cocoapods/v/CustomKeyboardTextField.svg) 8 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 9 | [![License](https://img.shields.io/github/license/giginet/CustomKeyboardTextField.svg)](https://github.com/giginet/CustomKeyboardTextField/blob/master/LICENSE.md) 10 | 11 | ![](https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/master/Documentation/Image/demo.gif) 12 | 13 | CustomKeyboardTextField provides easy way to make TextField with custom keyboards. 14 | 15 | This library is under development so interfaces might change. 16 | 17 | # Demo 18 | 19 | [Demo application](https://appetize.io/app/jv8ddk9ff2uwnf7hr508kbrkwg?device=iphone5s&scale=100&orientation=portrait&osVersion=9.3) is available on Appetize.io. 20 | 21 | # Usage 22 | 23 | ## Simple Picker 24 | 25 | ![](https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/master/Documentation/Image/picker.png) 26 | 27 | ```swift 28 | import CustomKeyboardTextField 29 | 30 | struct SimplePickerKeyboardDataSource: UIPickerViewKeyboardDataSource { 31 | let elements = ["Bulbasaur", "Charmander", "Squirtle"] 32 | } 33 | 34 | typealias SimplePickerTextField = PickerKeyboardTextField 35 | 36 | let pickerTextField = SimplePickerTextField() 37 | addSubView(pickerTextField) 38 | ``` 39 | 40 | If you'd like to change input text, override `inputText(for row: Int)`. 41 | 42 | You can also implement rich picker views. See [sample implementation](https://github.com/giginet/CustomKeyboardTextField/blob/master/CustomKeyboardTextFieldDemo/CustomKeyboard.swift#L10) for detail. 43 | 44 | ## Date Picker 45 | 46 | ![](https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/master/Documentation/Image/date_picker.png) 47 | 48 | 49 | ```swift 50 | import CustomKeyboardTextField 51 | 52 | struct DatePickerKeyboardDataSource: UIDatePickerKeyboardDataSource { 53 | let datePickerMode: UIDatePickerMode = .Date 54 | let timeFormat: String = "yyyy/MM/dd" 55 | } 56 | typealias DatePickerTextField = UIDatePickerKeyboardTextField 57 | ``` 58 | 59 | You can configure some parameters in `UIDatePickerKeyboardDataSource`. 60 | 61 | ## Custom Keyboard 62 | 63 | ![](https://raw.githubusercontent.com/giginet/CustomKeyboardTextField/master/Documentation/Image/custom.png) 64 | 65 | You can implement own custom keyboard easily. 66 | 67 | ### 1. Implement the custom keyboard view 68 | 69 | ```swift 70 | // Your custom view 71 | class MyCustomKeyboardView: UIView, CustomKeyboardView { 72 | weak var textField: UITextField? 73 | 74 | // current input text 75 | var inputText: String = "input text" 76 | 77 | // do something when keyboards are restored to default (optional) 78 | func reset() { 79 | } 80 | } 81 | ``` 82 | 83 | You can put some controls on your keyboard (button, switch, text fields etc...). 84 | When these are interacted, you execute `updateTextField()` then `inputText` is reflected in the text field. 85 | 86 | ### 2. Define `CustomKeyboardProvider` 87 | 88 | ```swift 89 | struct MyKeyboardProvider: CustomKeyboardProvider { 90 | weak var textField: UITextField! 91 | 92 | init(with textField: UITextField) { 93 | self.textField = textField 94 | } 95 | 96 | func inputView(with textField: UITextField) -> CustomKeyboardView? { 97 | // Return keyboard view 98 | let myKeyboardView = MyCustomKeyboardView() 99 | myKeyboardView.textField = textField 100 | return myKeyboardView 101 | } 102 | 103 | func inputAccessoryView(with textField: UITextField) -> CustomKeyboardAccessoryView? { 104 | // Return CustomKeyboardAccessoryView or nil 105 | // ToolbarKeyboardAccessoryView is built-in 106 | // Of cource, you can implement your own toolbars 107 | // CustomKeyboardAccessoryView has same interface with CustomKeyboardView 108 | let accessoryView = ToolbarKeyboardAccessoryView(with: textField) 109 | return accessoryView 110 | } 111 | } 112 | ``` 113 | 114 | ### 3. Define `CustomKeyboardTextField` 115 | 116 | ```swift 117 | typealias MyKeyboardTextField = CustomKeyboardTextField 118 | ``` 119 | 120 | See [sample implementation](https://github.com/giginet/CustomKeyboardTextField/blob/master/CustomKeyboardTextFieldDemo/CustomKeyboard.swift#L58) for detail. 121 | 122 | 123 | # Installation 124 | 125 | ## Carthage 126 | 127 | ``` 128 | github "giginet/CustomKeyboardTextField" 129 | ``` 130 | 131 | ## CocoaPods 132 | 133 | ```ruby 134 | use_frameworks! 135 | 136 | pod "CustomKeyboardTextField" 137 | ``` 138 | 139 | # Requirements 140 | 141 | - iOS 8 or above 142 | - Swift 3.0 143 | 144 | # Author 145 | 146 | giginet <> 147 | 148 | # LICENSE 149 | 150 | MIT License 151 | -------------------------------------------------------------------------------- /Sources/CustomKeyboardProvider.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | public protocol CustomKeyboardView: class { 4 | weak var textField: UITextField? { get } 5 | var inputText: String? { get } 6 | func updateTextField() 7 | func reset() 8 | } 9 | 10 | public extension CustomKeyboardView { 11 | var inputText: String? { 12 | return nil 13 | } 14 | 15 | func updateTextField() { 16 | textField?.text = inputText 17 | } 18 | 19 | func reset() { 20 | } 21 | } 22 | 23 | public protocol CustomKeyboardAccessoryView: CustomKeyboardView { 24 | } 25 | 26 | public protocol CustomKeyboardProvider { 27 | init() 28 | func inputView(with textField: UITextField) -> CustomKeyboardView? 29 | func inputAccessoryView(with textField: UITextField) -> CustomKeyboardAccessoryView? 30 | } 31 | 32 | public extension CustomKeyboardProvider { 33 | init() { 34 | self.init() 35 | } 36 | 37 | func inputAccessoryView(with textField: UITextField) -> CustomKeyboardAccessoryView? { 38 | return ToolbarKeyboardAccessoryView(with: textField) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/CustomKeyboardTextField.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | //! Project version number for CustomKeyboardTextField. 4 | FOUNDATION_EXPORT double CustomKeyboardTextFieldVersionNumber; 5 | 6 | //! Project version string for CustomKeyboardTextField. 7 | FOUNDATION_EXPORT const unsigned char CustomKeyboardTextFieldVersionString[]; 8 | 9 | // In this header, you should import all the public headers of your framework using statements like #import 10 | 11 | 12 | -------------------------------------------------------------------------------- /Sources/CustomKeyboardTextField.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | protocol CustomKeyboardTextFieldType: class { 4 | func editingDidCancel() 5 | } 6 | 7 | extension UITextField: CustomKeyboardTextFieldType { 8 | func editingDidCancel() { 9 | text = nil 10 | attributedText = nil 11 | leftView = nil 12 | rightView = nil 13 | } 14 | } 15 | 16 | open class CustomKeyboardTextField: UITextField, UITextFieldDelegate { 17 | var provider: CustomKeyboardProvider { 18 | return KeyboardViewProvider() 19 | } 20 | 21 | private(set) var customKeyboardView: CustomKeyboardView? { 22 | didSet { 23 | inputView = customKeyboardView as? UIView 24 | } 25 | } 26 | 27 | private(set) var customKeyboardAccessoryView: CustomKeyboardAccessoryView? { 28 | didSet { 29 | inputAccessoryView = customKeyboardAccessoryView as? UIView 30 | } 31 | } 32 | 33 | public convenience init() { 34 | self.init(frame: CGRect.zero) 35 | } 36 | 37 | public override init(frame: CGRect) { 38 | super.init(frame: frame) 39 | 40 | delegate = self 41 | 42 | setupCustomKeyboard() 43 | } 44 | 45 | required public init?(coder aDecoder: NSCoder) { 46 | fatalError("init(coder:) has not been implemented") 47 | } 48 | 49 | private func setupCustomKeyboard() { 50 | customKeyboardView = provider.inputView(with: self) 51 | customKeyboardAccessoryView = provider.inputAccessoryView(with: self) 52 | } 53 | 54 | override func editingDidCancel() { 55 | super.editingDidCancel() 56 | 57 | customKeyboardView?.reset() 58 | customKeyboardAccessoryView?.reset() 59 | } 60 | 61 | // MARK - UITextFieldDelegate 62 | 63 | open func textFieldDidBeginEditing(_ textField: UITextField) { 64 | customKeyboardView?.updateTextField() 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Sources/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 | -------------------------------------------------------------------------------- /Sources/Keyboards/ToolbarAccessoryView.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | open class ToolbarKeyboardAccessoryView: UIToolbar, CustomKeyboardAccessoryView { 4 | var toolbar = UIToolbar() 5 | let toolbarHeight: CGFloat = 44.0 6 | weak public var textField: UITextField? = nil 7 | 8 | required public init(with textField: UITextField) { 9 | super.init(frame: CGRect(x: 0, y: 0, width: 0, height: toolbarHeight)) 10 | self.textField = textField 11 | 12 | setItems(barItems, animated: true) 13 | } 14 | 15 | required public init?(coder aDecoder: NSCoder) { 16 | fatalError("init(coder:) has not been implemented") 17 | } 18 | 19 | func doneButtonDidTap(_ sender: UIBarButtonItem) { 20 | textField?.endEditing(true) 21 | } 22 | 23 | func cancelButtonDidTap(_ sender: UIBarButtonItem) { 24 | textField?.editingDidCancel() 25 | textField?.endEditing(true) 26 | } 27 | 28 | var barItems: [UIBarButtonItem] { 29 | let cancelItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelButtonDidTap(_:))) 30 | let spaceItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) 31 | let doneItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonDidTap(_:))) 32 | 33 | return [cancelItem, spaceItem, doneItem] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Keyboards/UIDatePickerKeyboard.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | public protocol UIDatePickerKeyboardDataSource { 4 | init() 5 | var calendar: Calendar { get } 6 | var date: Date { get } 7 | var locale: Locale { get } 8 | var timeZone: TimeZone { get } 9 | var maximumDate: Date? { get } 10 | var minimumDate: Date? { get } 11 | var minuteInterval: NSInteger { get } 12 | var countDownDuration: TimeInterval { get } 13 | var datePickerMode: UIDatePickerMode { get } 14 | var timeFormat: String { get } 15 | } 16 | 17 | public extension UIDatePickerKeyboardDataSource { 18 | var calendar: Calendar { 19 | return Calendar.current 20 | } 21 | 22 | var date: Date { 23 | return Date() 24 | } 25 | 26 | var locale: Locale { 27 | return Locale.current 28 | } 29 | 30 | var timeZone: TimeZone { 31 | return TimeZone.current 32 | } 33 | 34 | var maximumDate: Date? { 35 | return nil 36 | } 37 | 38 | var minimumDate: Date? { 39 | return nil 40 | } 41 | 42 | var minuteInterval: NSInteger { 43 | return 1 44 | } 45 | 46 | var countDownDuration: TimeInterval { 47 | return 0 48 | } 49 | 50 | var datePickerMode: UIDatePickerMode { 51 | return .dateAndTime 52 | } 53 | 54 | var timeFormat: String { 55 | return "yyyy/MM/dd HH:mm:ss Z" 56 | } 57 | } 58 | 59 | public class UIDatePickerKeyboard: UIDatePicker, CustomKeyboardView { 60 | public let datePickerKeyboardDataSource: DataSource 61 | weak public var textField: UITextField? = nil 62 | 63 | required public init?(coder aDecoder: NSCoder) { 64 | fatalError("init(coder:) has not been implemented") 65 | } 66 | 67 | required public init(with textField: UITextField, datePickerKeyboardViewDataSource: DataSource) { 68 | self.textField = textField 69 | self.datePickerKeyboardDataSource = datePickerKeyboardViewDataSource 70 | 71 | super.init(frame: CGRect.zero) 72 | 73 | calendar = datePickerKeyboardViewDataSource.calendar 74 | date = datePickerKeyboardViewDataSource.date 75 | locale = datePickerKeyboardViewDataSource.locale 76 | timeZone = datePickerKeyboardViewDataSource.timeZone 77 | maximumDate = datePickerKeyboardViewDataSource.maximumDate 78 | minimumDate = datePickerKeyboardViewDataSource.minimumDate 79 | minuteInterval = datePickerKeyboardViewDataSource.minuteInterval 80 | countDownDuration = datePickerKeyboardViewDataSource.countDownDuration 81 | datePickerMode = datePickerKeyboardViewDataSource.datePickerMode 82 | 83 | addTarget(self, action: #selector(dateIsChanged(_:)), for: .valueChanged) 84 | } 85 | 86 | func dateIsChanged(_ sender: UIDatePicker) { 87 | updateTextField() 88 | } 89 | 90 | open var inputText: String? { 91 | let formatter = DateFormatter() 92 | formatter.dateFormat = datePickerKeyboardDataSource.timeFormat 93 | formatter.timeZone = datePickerKeyboardDataSource.timeZone 94 | return formatter.string(from: date) 95 | } 96 | 97 | open func updateTextField() { 98 | textField?.text = inputText 99 | } 100 | 101 | open func reset() { 102 | date = datePickerKeyboardDataSource.date 103 | } 104 | } 105 | 106 | struct UIDatePickerKeyboardViewProvider: CustomKeyboardProvider { 107 | let dataSource: DataSource = DataSource() 108 | 109 | func inputView(with textField: UITextField) -> CustomKeyboardView? { 110 | let picker = UIDatePickerKeyboard(with: textField, datePickerKeyboardViewDataSource: dataSource) 111 | return picker 112 | } 113 | 114 | func inputAccessoryView(with textField: UITextField) -> CustomKeyboardAccessoryView? { 115 | let accessoryView = ToolbarKeyboardAccessoryView(with: textField) 116 | return accessoryView 117 | } 118 | } 119 | 120 | open class UIDatePickerKeyboardTextField: CustomKeyboardTextField> { 121 | public required init() { 122 | super.init(frame: CGRect.zero) 123 | } 124 | 125 | required public init?(coder aDecoder: NSCoder) { 126 | fatalError("init(coder:) has not been implemented") 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /Sources/Keyboards/UIPickerViewKeyboard.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | public protocol UIPickerViewKeyboardDataSource { 4 | init() 5 | var elements: [String] { get } 6 | func inputText(for row: Int) -> String? 7 | } 8 | 9 | public extension UIPickerViewKeyboardDataSource { 10 | func inputText(for row: Int) -> String? { 11 | return elements[row] 12 | } 13 | } 14 | 15 | open class UIPickerViewKeyboard: UIPickerView, UIPickerViewDelegate, CustomKeyboardView, UIPickerViewDataSource { 16 | public let pickerKeyboardDataSource: DataSource 17 | weak public var textField: UITextField? = nil 18 | 19 | required public init?(coder aDecoder: NSCoder) { 20 | fatalError("init(coder:) has not been implemented") 21 | } 22 | 23 | required public init(with textField: UITextField, pickerKeyboardViewDataSource: DataSource) { 24 | self.textField = textField 25 | self.pickerKeyboardDataSource = pickerKeyboardViewDataSource 26 | 27 | super.init(frame: CGRect.zero) 28 | 29 | dataSource = self 30 | delegate = self 31 | showsSelectionIndicator = true 32 | } 33 | 34 | open var inputText: String? { 35 | let row = selectedRow(inComponent: 0) 36 | return pickerKeyboardDataSource.inputText(for: row) 37 | } 38 | 39 | open func updateTextField() { 40 | textField?.text = inputText 41 | } 42 | 43 | open func reset() { 44 | selectRow(-1, inComponent: 0, animated: false) 45 | } 46 | 47 | // MARK - UIPickerViewDataSource 48 | 49 | open func numberOfComponents(in pickerView: UIPickerView) -> Int { 50 | return 1 51 | } 52 | 53 | open func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 54 | return pickerKeyboardDataSource.elements.count 55 | } 56 | 57 | // MARK - UIPickerViewDelegate 58 | 59 | open func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { 60 | return pickerKeyboardDataSource.elements[row] 61 | } 62 | 63 | open func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 64 | updateTextField() 65 | } 66 | } 67 | 68 | struct PickerKeyboardViewProvider: CustomKeyboardProvider { 69 | let dataSource: DataSource = DataSource() 70 | 71 | func inputView(with textField: UITextField) -> CustomKeyboardView? { 72 | let picker = UIPickerViewKeyboard(with: textField, pickerKeyboardViewDataSource: dataSource) 73 | return picker 74 | } 75 | 76 | func inputAccessoryView(with textField: UITextField) -> CustomKeyboardAccessoryView? { 77 | let accessoryView = ToolbarKeyboardAccessoryView(with: textField) 78 | return accessoryView 79 | } 80 | } 81 | 82 | open class PickerKeyboardTextField: CustomKeyboardTextField> { 83 | public required init() { 84 | super.init(frame: CGRect.zero) 85 | } 86 | 87 | required public init?(coder aDecoder: NSCoder) { 88 | fatalError("init(coder:) has not been implemented") 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Tests/CustomKeyboardTextField/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/CustomKeyboardTextField/UIDatePickerKeyboardTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import CustomKeyboardTextField 3 | 4 | private struct DateTimePickerKeyboardDataSource: UIDatePickerKeyboardDataSource { 5 | let timeZone: TimeZone = TimeZone(abbreviation: "JST")! 6 | } 7 | 8 | private typealias DateTimePickerTextField = UIDatePickerKeyboardTextField 9 | 10 | private struct DatePickerKeyboardDataSource: UIDatePickerKeyboardDataSource { 11 | let datePickerMode: UIDatePickerMode = .date 12 | let timeFormat: String = "yyyy/MM/dd" 13 | let timeZone: TimeZone = TimeZone(abbreviation: "JST")! 14 | } 15 | 16 | private typealias DatePickerTextField = UIDatePickerKeyboardTextField 17 | 18 | class UIDatePickerKeyboardTests: XCTestCase { 19 | var targetDate: Date { 20 | let formatter = DateFormatter() 21 | formatter.dateFormat = "yyyy/MM/dd HH:mm:ss Z" 22 | return formatter.date(from: "2016/08/06 12:25:30 +0900")! 23 | } 24 | 25 | func testAccessoryView() { 26 | let textField = DateTimePickerTextField() 27 | XCTAssertNotNil(textField.customKeyboardAccessoryView) 28 | XCTAssertNotNil(textField.inputAccessoryView) 29 | } 30 | 31 | func testDateTimePickerIsChanged() { 32 | let textField = DateTimePickerTextField() 33 | guard let pickerView = textField.customKeyboardView as? UIDatePickerKeyboard else { 34 | XCTFail() 35 | return 36 | } 37 | 38 | pickerView.setDate(targetDate, animated: false) 39 | pickerView.dateIsChanged(pickerView) 40 | 41 | XCTAssertEqual(textField.text, "2016/08/06 12:25:30 +0900") 42 | } 43 | 44 | func testDatePickerIsChanged() { 45 | let textField = DatePickerTextField() 46 | guard let pickerView = textField.customKeyboardView as? UIDatePickerKeyboard else { 47 | XCTFail() 48 | return 49 | } 50 | 51 | pickerView.setDate(targetDate, animated: false) 52 | pickerView.dateIsChanged(pickerView) 53 | 54 | XCTAssertEqual(textField.text, "2016/08/06") 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Tests/CustomKeyboardTextField/UIPickerViewKeyboardTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import CustomKeyboardTextField 3 | 4 | private struct PokemonPickerKeyboardDataSource: UIPickerViewKeyboardDataSource { 5 | let elements = ["Bulbasaur", "Charmander", "Squirtle"] 6 | } 7 | 8 | private typealias PokemonPickerTextField = PickerKeyboardTextField 9 | 10 | private struct PokemonTypePickerKeyboardDataSource: UIPickerViewKeyboardDataSource { 11 | let elements = ["Bulbasaur", "Charmander", "Squirtle"] 12 | 13 | func inputText(for row: Int) -> String? { 14 | return ["Leaf", "Fire", "Water"][row] 15 | } 16 | } 17 | 18 | private typealias PokemonTypePickerTextField = PickerKeyboardTextField 19 | 20 | class UIPickerViewKeyboardTests: XCTestCase { 21 | func testAccessoryView() { 22 | let textField = PokemonPickerTextField() 23 | XCTAssertNotNil(textField.customKeyboardAccessoryView) 24 | XCTAssertNotNil(textField.inputAccessoryView) 25 | } 26 | 27 | func testPickerIsChanged() { 28 | let textField = PokemonPickerTextField() 29 | guard let pickerView = textField.customKeyboardView as? UIPickerView else { 30 | XCTFail() 31 | return 32 | } 33 | 34 | pickerView.selectRow(0, inComponent: 0, animated: false) 35 | pickerView.delegate?.pickerView?(pickerView, didSelectRow: 0, inComponent: 0) 36 | XCTAssertEqual(textField.text, "Bulbasaur") 37 | 38 | pickerView.selectRow(1, inComponent: 0, animated: false) 39 | pickerView.delegate?.pickerView?(pickerView, didSelectRow: 1, inComponent: 0) 40 | XCTAssertEqual(textField.text, "Charmander") 41 | 42 | pickerView.selectRow(2, inComponent: 0, animated: false) 43 | pickerView.delegate?.pickerView?(pickerView, didSelectRow: 2, inComponent: 0) 44 | XCTAssertEqual(textField.text, "Squirtle") 45 | } 46 | 47 | func testPickerIsChangedWithInputText() { 48 | let textField = PokemonTypePickerTextField() 49 | guard let pickerView = textField.customKeyboardView as? UIPickerView else { 50 | XCTFail() 51 | return 52 | } 53 | 54 | pickerView.selectRow(0, inComponent: 0, animated: false) 55 | pickerView.delegate?.pickerView?(pickerView, didSelectRow: 0, inComponent: 0) 56 | XCTAssertEqual(textField.text, "Leaf") 57 | 58 | pickerView.selectRow(1, inComponent: 0, animated: false) 59 | pickerView.delegate?.pickerView?(pickerView, didSelectRow: 1, inComponent: 0) 60 | XCTAssertEqual(textField.text, "Fire") 61 | 62 | pickerView.selectRow(2, inComponent: 0, animated: false) 63 | pickerView.delegate?.pickerView?(pickerView, didSelectRow: 2, inComponent: 0) 64 | XCTAssertEqual(textField.text, "Water") 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: yes 4 | coverage: 5 | ignore: 6 | - Tests/CustomKeyboardTextField/*.swift 7 | precision: 2 8 | round: down 9 | range: 70...100 10 | status: 11 | project: false 12 | patch: true 13 | changes: true 14 | comment: 15 | layout: "header, diff, changes, uncovered" 16 | behavior: default 17 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | fastlane_version "1.99.0" 2 | 3 | default_platform :ios 4 | 5 | platform :ios do 6 | project_name = 'CustomKeyboardTextField' 7 | scheme_name = 'CustomKeyboardTextFieldDemo' 8 | 9 | desc "Deploy demo application to Appetize.io" 10 | lane :deploy_to_appetize do 11 | base_build_dir = File.expand_path('build') 12 | 13 | xcodebuild(project: "#{project_name}.xcodeproj", 14 | scheme: scheme_name, 15 | xcargs: "CONFIGURATION_BUILD_DIR=#{base_build_dir}", 16 | sdk: 'iphonesimulator') 17 | 18 | app_path = File.join(base_build_dir, "#{scheme_name}.app") 19 | zip_path = File.join(base_build_dir, "#{scheme_name}.app.zip") 20 | zip(path: app_path, 21 | output_path: zip_path) 22 | 23 | note = last_git_commit[:message] 24 | appetize(path: zip_path, note: note) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ================ 3 | # Installation 4 | ``` 5 | sudo gem install fastlane 6 | ``` 7 | # Available Actions 8 | ## iOS 9 | ### ios deploy_to_appetize 10 | ``` 11 | fastlane ios deploy_to_appetize 12 | ``` 13 | Deploy demo application to Appetize.io 14 | 15 | ---- 16 | 17 | This README.md is auto-generated and will be re-generated every time to run [fastlane](https://fastlane.tools). 18 | More information about fastlane can be found on [https://fastlane.tools](https://fastlane.tools). 19 | The documentation of fastlane can be found on [GitHub](https://github.com/fastlane/fastlane/tree/master/fastlane). --------------------------------------------------------------------------------