├── Form Input Accessory View Demo.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── Form Input Accessory View Demo ├── AppDelegate.h ├── AppDelegate.m ├── Default-568h@2x.png ├── Default.png ├── Default@2x.png ├── DemoViewController.h ├── DemoViewController.m ├── Form Input Accessory View Demo-Info.plist ├── Form Input Accessory View Demo-Prefix.pch ├── MainStoryboard.storyboard └── main.m ├── README.md ├── Screenshots └── XCDFormInputAccessoryView.png └── XCDFormInputAccessoryView ├── XCDFormInputAccessoryView.h └── XCDFormInputAccessoryView.m /Form Input Accessory View Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C215427C164FD1C800262EB1 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C2154275164FD1C800262EB1 /* Default-568h@2x.png */; }; 11 | C215427D164FD1C800262EB1 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = C2154276164FD1C800262EB1 /* Default.png */; }; 12 | C215427E164FD1C800262EB1 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C2154277164FD1C800262EB1 /* Default@2x.png */; }; 13 | C2154280164FD1C800262EB1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C215427A164FD1C800262EB1 /* main.m */; }; 14 | C2154281164FD1C800262EB1 /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C215427B164FD1C800262EB1 /* MainStoryboard.storyboard */; }; 15 | C2F07143164DCA75008F4BA2 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2F07142164DCA75008F4BA2 /* UIKit.framework */; }; 16 | C2F07145164DCA75008F4BA2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2F07144164DCA75008F4BA2 /* Foundation.framework */; }; 17 | C2F07147164DCA75008F4BA2 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2F07146164DCA75008F4BA2 /* CoreGraphics.framework */; }; 18 | C2F07153164DCA75008F4BA2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C2F07152164DCA75008F4BA2 /* AppDelegate.m */; }; 19 | C2F0715F164DCA75008F4BA2 /* DemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C2F0715E164DCA75008F4BA2 /* DemoViewController.m */; }; 20 | C2F0716C164F0E32008F4BA2 /* XCDFormInputAccessoryView.m in Sources */ = {isa = PBXBuildFile; fileRef = C2F0716B164F0E32008F4BA2 /* XCDFormInputAccessoryView.m */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | C2154275164FD1C800262EB1 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 25 | C2154276164FD1C800262EB1 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 26 | C2154277164FD1C800262EB1 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 27 | C2154278164FD1C800262EB1 /* Form Input Accessory View Demo-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Form Input Accessory View Demo-Info.plist"; sourceTree = ""; }; 28 | C2154279164FD1C800262EB1 /* Form Input Accessory View Demo-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Form Input Accessory View Demo-Prefix.pch"; sourceTree = ""; }; 29 | C215427A164FD1C800262EB1 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 30 | C215427B164FD1C800262EB1 /* MainStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MainStoryboard.storyboard; sourceTree = ""; }; 31 | C2F0713E164DCA75008F4BA2 /* Form Input Accessory View Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Form Input Accessory View Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | C2F07142164DCA75008F4BA2 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 33 | C2F07144164DCA75008F4BA2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 34 | C2F07146164DCA75008F4BA2 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 35 | C2F07151164DCA75008F4BA2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 36 | C2F07152164DCA75008F4BA2 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 37 | C2F0715D164DCA75008F4BA2 /* DemoViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DemoViewController.h; sourceTree = ""; }; 38 | C2F0715E164DCA75008F4BA2 /* DemoViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DemoViewController.m; sourceTree = ""; }; 39 | C2F0716A164F0E32008F4BA2 /* XCDFormInputAccessoryView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCDFormInputAccessoryView.h; sourceTree = ""; }; 40 | C2F0716B164F0E32008F4BA2 /* XCDFormInputAccessoryView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCDFormInputAccessoryView.m; sourceTree = ""; }; 41 | /* End PBXFileReference section */ 42 | 43 | /* Begin PBXFrameworksBuildPhase section */ 44 | C2F0713B164DCA75008F4BA2 /* Frameworks */ = { 45 | isa = PBXFrameworksBuildPhase; 46 | buildActionMask = 2147483647; 47 | files = ( 48 | C2F07143164DCA75008F4BA2 /* UIKit.framework in Frameworks */, 49 | C2F07145164DCA75008F4BA2 /* Foundation.framework in Frameworks */, 50 | C2F07147164DCA75008F4BA2 /* CoreGraphics.framework in Frameworks */, 51 | ); 52 | runOnlyForDeploymentPostprocessing = 0; 53 | }; 54 | /* End PBXFrameworksBuildPhase section */ 55 | 56 | /* Begin PBXGroup section */ 57 | C2F07133164DCA75008F4BA2 = { 58 | isa = PBXGroup; 59 | children = ( 60 | C2F07169164F0E1E008F4BA2 /* XCDFormInputAccessoryView */, 61 | C2F07148164DCA75008F4BA2 /* Form Input Accessory View Demo */, 62 | C2F07141164DCA75008F4BA2 /* Frameworks */, 63 | C2F0713F164DCA75008F4BA2 /* Products */, 64 | ); 65 | sourceTree = ""; 66 | }; 67 | C2F0713F164DCA75008F4BA2 /* Products */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | C2F0713E164DCA75008F4BA2 /* Form Input Accessory View Demo.app */, 71 | ); 72 | name = Products; 73 | sourceTree = ""; 74 | }; 75 | C2F07141164DCA75008F4BA2 /* Frameworks */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | C2F07142164DCA75008F4BA2 /* UIKit.framework */, 79 | C2F07144164DCA75008F4BA2 /* Foundation.framework */, 80 | C2F07146164DCA75008F4BA2 /* CoreGraphics.framework */, 81 | ); 82 | name = Frameworks; 83 | sourceTree = ""; 84 | }; 85 | C2F07148164DCA75008F4BA2 /* Form Input Accessory View Demo */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | C2F07151164DCA75008F4BA2 /* AppDelegate.h */, 89 | C2F07152164DCA75008F4BA2 /* AppDelegate.m */, 90 | C2154275164FD1C800262EB1 /* Default-568h@2x.png */, 91 | C2154276164FD1C800262EB1 /* Default.png */, 92 | C2154277164FD1C800262EB1 /* Default@2x.png */, 93 | C2F0715D164DCA75008F4BA2 /* DemoViewController.h */, 94 | C2F0715E164DCA75008F4BA2 /* DemoViewController.m */, 95 | C2154278164FD1C800262EB1 /* Form Input Accessory View Demo-Info.plist */, 96 | C2154279164FD1C800262EB1 /* Form Input Accessory View Demo-Prefix.pch */, 97 | C215427A164FD1C800262EB1 /* main.m */, 98 | C215427B164FD1C800262EB1 /* MainStoryboard.storyboard */, 99 | ); 100 | path = "Form Input Accessory View Demo"; 101 | sourceTree = ""; 102 | }; 103 | C2F07169164F0E1E008F4BA2 /* XCDFormInputAccessoryView */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | C2F0716A164F0E32008F4BA2 /* XCDFormInputAccessoryView.h */, 107 | C2F0716B164F0E32008F4BA2 /* XCDFormInputAccessoryView.m */, 108 | ); 109 | path = XCDFormInputAccessoryView; 110 | sourceTree = ""; 111 | }; 112 | /* End PBXGroup section */ 113 | 114 | /* Begin PBXNativeTarget section */ 115 | C2F0713D164DCA75008F4BA2 /* Form Input Accessory View Demo */ = { 116 | isa = PBXNativeTarget; 117 | buildConfigurationList = C2F07162164DCA75008F4BA2 /* Build configuration list for PBXNativeTarget "Form Input Accessory View Demo" */; 118 | buildPhases = ( 119 | C2F0713A164DCA75008F4BA2 /* Sources */, 120 | C2F0713B164DCA75008F4BA2 /* Frameworks */, 121 | C2F0713C164DCA75008F4BA2 /* Resources */, 122 | ); 123 | buildRules = ( 124 | ); 125 | dependencies = ( 126 | ); 127 | name = "Form Input Accessory View Demo"; 128 | productName = "Form Input Accessory View Demo"; 129 | productReference = C2F0713E164DCA75008F4BA2 /* Form Input Accessory View Demo.app */; 130 | productType = "com.apple.product-type.application"; 131 | }; 132 | /* End PBXNativeTarget section */ 133 | 134 | /* Begin PBXProject section */ 135 | C2F07135164DCA75008F4BA2 /* Project object */ = { 136 | isa = PBXProject; 137 | attributes = { 138 | LastUpgradeCheck = 0450; 139 | ORGANIZATIONNAME = "Cédric Luthi"; 140 | }; 141 | buildConfigurationList = C2F07138164DCA75008F4BA2 /* Build configuration list for PBXProject "Form Input Accessory View Demo" */; 142 | compatibilityVersion = "Xcode 3.2"; 143 | developmentRegion = English; 144 | hasScannedForEncodings = 0; 145 | knownRegions = ( 146 | en, 147 | ); 148 | mainGroup = C2F07133164DCA75008F4BA2; 149 | productRefGroup = C2F0713F164DCA75008F4BA2 /* Products */; 150 | projectDirPath = ""; 151 | projectRoot = ""; 152 | targets = ( 153 | C2F0713D164DCA75008F4BA2 /* Form Input Accessory View Demo */, 154 | ); 155 | }; 156 | /* End PBXProject section */ 157 | 158 | /* Begin PBXResourcesBuildPhase section */ 159 | C2F0713C164DCA75008F4BA2 /* Resources */ = { 160 | isa = PBXResourcesBuildPhase; 161 | buildActionMask = 2147483647; 162 | files = ( 163 | C215427C164FD1C800262EB1 /* Default-568h@2x.png in Resources */, 164 | C215427D164FD1C800262EB1 /* Default.png in Resources */, 165 | C215427E164FD1C800262EB1 /* Default@2x.png in Resources */, 166 | C2154281164FD1C800262EB1 /* MainStoryboard.storyboard in Resources */, 167 | ); 168 | runOnlyForDeploymentPostprocessing = 0; 169 | }; 170 | /* End PBXResourcesBuildPhase section */ 171 | 172 | /* Begin PBXSourcesBuildPhase section */ 173 | C2F0713A164DCA75008F4BA2 /* Sources */ = { 174 | isa = PBXSourcesBuildPhase; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | C2154280164FD1C800262EB1 /* main.m in Sources */, 178 | C2F07153164DCA75008F4BA2 /* AppDelegate.m in Sources */, 179 | C2F0715F164DCA75008F4BA2 /* DemoViewController.m in Sources */, 180 | C2F0716C164F0E32008F4BA2 /* XCDFormInputAccessoryView.m in Sources */, 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | }; 184 | /* End PBXSourcesBuildPhase section */ 185 | 186 | /* Begin XCBuildConfiguration section */ 187 | C2F07160164DCA75008F4BA2 /* Debug */ = { 188 | isa = XCBuildConfiguration; 189 | buildSettings = { 190 | ALWAYS_SEARCH_USER_PATHS = NO; 191 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 192 | CLANG_CXX_LIBRARY = "libc++"; 193 | CLANG_ENABLE_OBJC_ARC = YES; 194 | CLANG_WARN_EMPTY_BODY = YES; 195 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 196 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 197 | COPY_PHASE_STRIP = NO; 198 | CURRENT_PROJECT_VERSION = 1.0.0; 199 | GCC_C_LANGUAGE_STANDARD = gnu99; 200 | GCC_DYNAMIC_NO_PIC = NO; 201 | GCC_OPTIMIZATION_LEVEL = 0; 202 | GCC_PREPROCESSOR_DEFINITIONS = ( 203 | "DEBUG=1", 204 | "$(inherited)", 205 | ); 206 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 207 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 208 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 209 | GCC_WARN_UNUSED_VARIABLE = YES; 210 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 211 | ONLY_ACTIVE_ARCH = YES; 212 | SDKROOT = iphoneos; 213 | TARGETED_DEVICE_FAMILY = "1,2"; 214 | WARNING_CFLAGS = ( 215 | "-Weverything", 216 | "-Wno-objc-missing-property-synthesis", 217 | ); 218 | }; 219 | name = Debug; 220 | }; 221 | C2F07161164DCA75008F4BA2 /* Release */ = { 222 | isa = XCBuildConfiguration; 223 | buildSettings = { 224 | ALWAYS_SEARCH_USER_PATHS = NO; 225 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 226 | CLANG_CXX_LIBRARY = "libc++"; 227 | CLANG_ENABLE_OBJC_ARC = YES; 228 | CLANG_WARN_EMPTY_BODY = YES; 229 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 230 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 231 | COPY_PHASE_STRIP = YES; 232 | CURRENT_PROJECT_VERSION = 1.0.0; 233 | GCC_C_LANGUAGE_STANDARD = gnu99; 234 | GCC_PREPROCESSOR_DEFINITIONS = "NS_BLOCK_ASSERTIONS=1"; 235 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 236 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 237 | GCC_WARN_UNUSED_VARIABLE = YES; 238 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 239 | SDKROOT = iphoneos; 240 | TARGETED_DEVICE_FAMILY = "1,2"; 241 | VALIDATE_PRODUCT = YES; 242 | WARNING_CFLAGS = ( 243 | "-Weverything", 244 | "-Wno-objc-missing-property-synthesis", 245 | ); 246 | }; 247 | name = Release; 248 | }; 249 | C2F07163164DCA75008F4BA2 /* Debug */ = { 250 | isa = XCBuildConfiguration; 251 | buildSettings = { 252 | FRAMEWORK_SEARCH_PATHS = ( 253 | "$(inherited)", 254 | "\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"", 255 | ); 256 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 257 | GCC_PREFIX_HEADER = "Form Input Accessory View Demo/Form Input Accessory View Demo-Prefix.pch"; 258 | INFOPLIST_FILE = "Form Input Accessory View Demo/Form Input Accessory View Demo-Info.plist"; 259 | PRODUCT_NAME = "Form Input Accessory View Demo"; 260 | WRAPPER_EXTENSION = app; 261 | }; 262 | name = Debug; 263 | }; 264 | C2F07164164DCA75008F4BA2 /* Release */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | FRAMEWORK_SEARCH_PATHS = ( 268 | "$(inherited)", 269 | "\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"", 270 | ); 271 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 272 | GCC_PREFIX_HEADER = "Form Input Accessory View Demo/Form Input Accessory View Demo-Prefix.pch"; 273 | INFOPLIST_FILE = "Form Input Accessory View Demo/Form Input Accessory View Demo-Info.plist"; 274 | PRODUCT_NAME = "Form Input Accessory View Demo"; 275 | WRAPPER_EXTENSION = app; 276 | }; 277 | name = Release; 278 | }; 279 | /* End XCBuildConfiguration section */ 280 | 281 | /* Begin XCConfigurationList section */ 282 | C2F07138164DCA75008F4BA2 /* Build configuration list for PBXProject "Form Input Accessory View Demo" */ = { 283 | isa = XCConfigurationList; 284 | buildConfigurations = ( 285 | C2F07160164DCA75008F4BA2 /* Debug */, 286 | C2F07161164DCA75008F4BA2 /* Release */, 287 | ); 288 | defaultConfigurationIsVisible = 0; 289 | defaultConfigurationName = Release; 290 | }; 291 | C2F07162164DCA75008F4BA2 /* Build configuration list for PBXNativeTarget "Form Input Accessory View Demo" */ = { 292 | isa = XCConfigurationList; 293 | buildConfigurations = ( 294 | C2F07163164DCA75008F4BA2 /* Debug */, 295 | C2F07164164DCA75008F4BA2 /* Release */, 296 | ); 297 | defaultConfigurationIsVisible = 0; 298 | defaultConfigurationName = Release; 299 | }; 300 | /* End XCConfigurationList section */ 301 | }; 302 | rootObject = C2F07135164DCA75008F4BA2 /* Project object */; 303 | } 304 | -------------------------------------------------------------------------------- /Form Input Accessory View Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Form Input Accessory View Demo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Form Accessory View Demo 4 | // 5 | // Created by Cédric Luthi on 10.11.12. 6 | // Copyright (c) 2012 Cédric Luthi. All rights reserved. 7 | // 8 | 9 | @interface AppDelegate : UIResponder 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /Form Input Accessory View Demo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Form Accessory View Demo 4 | // 5 | // Created by Cédric Luthi on 10.11.12. 6 | // Copyright (c) 2012 Cédric Luthi. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | @synthesize window = _window; 14 | 15 | - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | return YES; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Form Input Accessory View Demo/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xced/XCDFormInputAccessoryView/518fcbd9c6bab7e363c5d186efad99c7c2546a7e/Form Input Accessory View Demo/Default-568h@2x.png -------------------------------------------------------------------------------- /Form Input Accessory View Demo/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xced/XCDFormInputAccessoryView/518fcbd9c6bab7e363c5d186efad99c7c2546a7e/Form Input Accessory View Demo/Default.png -------------------------------------------------------------------------------- /Form Input Accessory View Demo/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xced/XCDFormInputAccessoryView/518fcbd9c6bab7e363c5d186efad99c7c2546a7e/Form Input Accessory View Demo/Default@2x.png -------------------------------------------------------------------------------- /Form Input Accessory View Demo/DemoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoViewController.h 3 | // Form Accessory View Demo 4 | // 5 | // Created by Cédric Luthi on 10.11.12. 6 | // Copyright (c) 2012 Cédric Luthi. All rights reserved. 7 | // 8 | 9 | @interface DemoViewController : UITableViewController 10 | 11 | @property (nonatomic, strong) IBOutletCollection(UIView) NSArray *textInputs; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Form Input Accessory View Demo/DemoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoViewController.m 3 | // Form Accessory View Demo 4 | // 5 | // Created by Cédric Luthi on 10.11.12. 6 | // Copyright (c) 2012 Cédric Luthi. All rights reserved. 7 | // 8 | 9 | #import "DemoViewController.h" 10 | 11 | #import "XCDFormInputAccessoryView.h" 12 | 13 | @implementation DemoViewController 14 | { 15 | XCDFormInputAccessoryView *_inputAccessoryView; 16 | } 17 | 18 | - (void) setTextInputs:(NSArray *)textInputs 19 | { 20 | // Some day, IBOutletCollection will be properly sorted, in the meantime, sort it! 21 | _textInputs = [textInputs sortedArrayUsingComparator:^NSComparisonResult(UIView *view1, UIView *view2) { 22 | return [@(view1.tag) compare:@(view2.tag)]; 23 | }]; 24 | } 25 | 26 | - (void) viewDidLoad 27 | { 28 | for (UIView *textInput in self.textInputs) 29 | { 30 | UIView *view = [textInput isKindOfClass:[UITextField class]] ? textInput.superview : textInput; 31 | view.layer.borderColor = [UIColor grayColor].CGColor; 32 | view.layer.borderWidth = 1; 33 | view.layer.cornerRadius = 8; 34 | } 35 | 36 | UITapGestureRecognizer *tapGestureRecognizer2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(takeScreenshot:)]; 37 | tapGestureRecognizer2.numberOfTapsRequired = 2; 38 | UITapGestureRecognizer *tapGestureRecognizer3 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(takeScreenshot:)]; 39 | tapGestureRecognizer3.numberOfTapsRequired = 3; 40 | [tapGestureRecognizer2 requireGestureRecognizerToFail:tapGestureRecognizer3]; 41 | [self.view addGestureRecognizer:tapGestureRecognizer2]; 42 | [self.view addGestureRecognizer:tapGestureRecognizer3]; 43 | } 44 | 45 | - (void) takeScreenshot:(UITapGestureRecognizer *)gestureRecognizer 46 | { 47 | CGFloat scale = gestureRecognizer.numberOfTapsRequired - 1.0f; 48 | UIGraphicsBeginImageContextWithOptions(self.inputAccessoryView.frame.size, NO, scale); 49 | CGContextRef context = UIGraphicsGetCurrentContext(); 50 | [self.inputAccessoryView.layer renderInContext:context]; 51 | UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext(); 52 | UIGraphicsEndImageContext(); 53 | 54 | NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; 55 | [[NSFileManager defaultManager] createDirectoryAtPath:documentsDirectory withIntermediateDirectories:YES attributes:nil error:NULL]; 56 | NSString *scaleString = scale != 1.f ? [NSString stringWithFormat:@"@%gx", scale] : @""; 57 | NSString *screenshotName = [NSString stringWithFormat:@"%@%@.png", [[self inputAccessoryView] class], scaleString]; 58 | NSString *screenshotPath = [documentsDirectory stringByAppendingPathComponent:screenshotName]; 59 | [UIImagePNGRepresentation(screenshot) writeToFile:screenshotPath atomically:YES]; 60 | system([[NSString stringWithFormat:@"open \"%@\"", screenshotPath] fileSystemRepresentation]); 61 | } 62 | 63 | - (UIView *) inputAccessoryView 64 | { 65 | if (!_inputAccessoryView) 66 | { 67 | _inputAccessoryView = [[XCDFormInputAccessoryView alloc] initWithResponders:self.textInputs]; 68 | //_inputAccessoryView = [[XCDFormInputAccessoryView alloc] init]; 69 | //_inputAccessoryView = [[NSClassFromString(@"UIWebFormAccessory") alloc] init]; 70 | } 71 | return _inputAccessoryView; 72 | } 73 | 74 | - (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 75 | { 76 | return indexPath.row == 2 ? 200 : tableView.rowHeight; 77 | } 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /Form Input Accessory View Demo/Form Input Accessory View Demo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | ch.pitaya.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundleShortVersionString 18 | ${CURRENT_PROJECT_VERSION} 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIMainStoryboardFile 24 | MainStoryboard 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Form Input Accessory View Demo/Form Input Accessory View Demo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Form Accessory View Demo' target in the 'Form Accessory View Demo' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #import 15 | #endif 16 | -------------------------------------------------------------------------------- /Form Input Accessory View Demo/MainStoryboard.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 | 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 | 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 | 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 | -------------------------------------------------------------------------------- /Form Input Accessory View Demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Form Accessory View Demo 4 | // 5 | // Created by Cédric Luthi on 10.11.12. 6 | // Copyright (c) 2012 Cédric Luthi. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | @autoreleasepool 14 | { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | About 2 | ===== 3 | `XCDFormInputAccessoryView` is a view to be used above the keyboard with *previous*, *next* and *done* buttons for navigating text fields. 4 | 5 | ![screenshot](https://github.com/0xced/XCDFormInputAccessoryView/raw/master/Screenshots/XCDFormInputAccessoryView.png) 6 | 7 | `XCDFormInputAccessoryView` uses ARC (Automatic Reference Counting) and must be built with Xcode 4.5 or greater. It has been tested on iOS 4, 5 and 6. 8 | 9 | Usage 10 | ===== 11 | In your `UIViewController` subclass, redeclare the `inputAccessoryView` property and create a new instance of `XCDFormInputAccessoryView`, for example in your `viewDidLoad` method: 12 | 13 | #import "XCDFormInputAccessoryView.h" 14 | 15 | @interface MyViewController () 16 | @property (nonatomic, strong) XCDFormInputAccessoryView *inputAccessoryView; 17 | @end 18 | 19 | @implementation MyViewController 20 | - (void) viewDidLoad 21 | { 22 | [super viewDidLoad]; 23 | self.inputAccessoryView = [XCDFormInputAccessoryView new]; 24 | } 25 | @end 26 | 27 | If you want to have total control over what the **Previous** and **Next** buttons do, you should initialize `XCDFormInputAccessoryView` with the `initWithResponders:` method instead and pass an array of `UIResponder` instances. If you do not supply an array of responders, then `XCDFormInputAccessoryView` uses the following heuristic to find which text input views will be used: 28 | 29 | 1. Find all text fields and editable text views in the key window 30 | 2. Sort them using their frame origin vertical position 31 | 32 | License 33 | ======= 34 | The MIT License (MIT) 35 | Copyright (c) 2012 Cédric Luthi 36 | 37 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 38 | 39 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Screenshots/XCDFormInputAccessoryView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xced/XCDFormInputAccessoryView/518fcbd9c6bab7e363c5d186efad99c7c2546a7e/Screenshots/XCDFormInputAccessoryView.png -------------------------------------------------------------------------------- /XCDFormInputAccessoryView/XCDFormInputAccessoryView.h: -------------------------------------------------------------------------------- 1 | // 2 | // XCDFormInputAccessoryView.h 3 | // 4 | // Created by Cédric Luthi on 2012-11-10 5 | // Copyright (c) 2012 Cédric Luthi. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface XCDFormInputAccessoryView : UIView 11 | 12 | - (id) initWithResponders:(NSArray *)responders; // Objects must be UIResponder instances 13 | 14 | @property (nonatomic, strong) NSArray *responders; 15 | 16 | @property (nonatomic, assign) BOOL hasDoneButton; // Defaults to YES on iPhone, NO on iPad 17 | 18 | - (void) setHasDoneButton:(BOOL)hasDoneButton animated:(BOOL)animated; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /XCDFormInputAccessoryView/XCDFormInputAccessoryView.m: -------------------------------------------------------------------------------- 1 | // 2 | // XCDFormInputAccessoryView.m 3 | // 4 | // Created by Cédric Luthi on 2012-11-10 5 | // Copyright (c) 2012 Cédric Luthi. All rights reserved. 6 | // 7 | 8 | #import "XCDFormInputAccessoryView.h" 9 | 10 | static NSString * UIKitLocalizedString(NSString *string) 11 | { 12 | NSBundle *UIKitBundle = [NSBundle bundleForClass:[UIApplication class]]; 13 | return UIKitBundle ? [UIKitBundle localizedStringForKey:string value:string table:nil] : string; 14 | } 15 | 16 | static NSArray * EditableTextInputsInView(UIView *view) 17 | { 18 | NSMutableArray *textInputs = [NSMutableArray new]; 19 | for (UIView *subview in view.subviews) 20 | { 21 | BOOL isTextField = [subview isKindOfClass:[UITextField class]]; 22 | BOOL isEditableTextView = [subview isKindOfClass:[UITextView class]] && [(UITextView *)subview isEditable]; 23 | if (isTextField || isEditableTextView) 24 | [textInputs addObject:subview]; 25 | else 26 | [textInputs addObjectsFromArray:EditableTextInputsInView(subview)]; 27 | } 28 | return textInputs; 29 | } 30 | 31 | @implementation XCDFormInputAccessoryView 32 | { 33 | UIToolbar *_toolbar; 34 | } 35 | 36 | - (id) initWithFrame:(CGRect)frame 37 | { 38 | return [self initWithResponders:nil]; 39 | } 40 | 41 | - (id) initWithResponders:(NSArray *)responders 42 | { 43 | if (!(self = [super initWithFrame:CGRectZero])) 44 | return nil; 45 | 46 | _responders = responders; 47 | 48 | _toolbar = [[UIToolbar alloc] init]; 49 | _toolbar.tintColor = nil; 50 | _toolbar.barStyle = UIBarStyleBlack; 51 | _toolbar.translucent = YES; 52 | _toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth; 53 | UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:@[ UIKitLocalizedString(@"Previous"), UIKitLocalizedString(@"Next") ]]; 54 | [segmentedControl addTarget:self action:@selector(selectAdjacentResponder:) forControlEvents:UIControlEventValueChanged]; 55 | segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar; 56 | segmentedControl.momentary = YES; 57 | UIBarButtonItem *segmentedControlBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:segmentedControl]; 58 | UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 59 | _toolbar.items = @[ segmentedControlBarButtonItem, flexibleSpace ]; 60 | self.hasDoneButton = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone; 61 | 62 | [self addSubview:_toolbar]; 63 | 64 | self.frame = _toolbar.frame = (CGRect){CGPointZero, [_toolbar sizeThatFits:CGSizeZero]}; 65 | 66 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textInputDidBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil]; 67 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textInputDidBeginEditing:) name:UITextViewTextDidBeginEditingNotification object:nil]; 68 | 69 | return self; 70 | } 71 | 72 | - (void) dealloc 73 | { 74 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 75 | } 76 | 77 | - (void) updateSegmentedControl 78 | { 79 | NSArray *responders = self.responders; 80 | if ([responders count] == 0) 81 | return; 82 | 83 | UISegmentedControl *segmentedControl = (UISegmentedControl *)[_toolbar.items[0] customView]; 84 | BOOL isFirst = [[responders objectAtIndex:0] isFirstResponder]; 85 | BOOL isLast = [[responders lastObject] isFirstResponder]; 86 | [segmentedControl setEnabled:!isFirst forSegmentAtIndex:0]; 87 | [segmentedControl setEnabled:!isLast forSegmentAtIndex:1]; 88 | } 89 | 90 | - (void) willMoveToWindow:(UIWindow *)window 91 | { 92 | if (!window) 93 | return; 94 | 95 | [self updateSegmentedControl]; 96 | } 97 | 98 | - (void) textInputDidBeginEditing:(NSNotification *)notification 99 | { 100 | [self updateSegmentedControl]; 101 | } 102 | 103 | - (NSArray *) responders 104 | { 105 | if (_responders) 106 | return _responders; 107 | 108 | NSArray *textInputs = EditableTextInputsInView([[UIApplication sharedApplication] keyWindow]); 109 | return [textInputs sortedArrayUsingComparator:^NSComparisonResult(UIView *textInput1, UIView *textInput2) { 110 | UIView *commonAncestorView = textInput1.superview; 111 | while (commonAncestorView && ![textInput2 isDescendantOfView:commonAncestorView]) 112 | commonAncestorView = commonAncestorView.superview; 113 | 114 | CGRect frame1 = [textInput1 convertRect:textInput1.bounds toView:commonAncestorView]; 115 | CGRect frame2 = [textInput2 convertRect:textInput2.bounds toView:commonAncestorView]; 116 | return [@(CGRectGetMinY(frame1)) compare:@(CGRectGetMinY(frame2))]; 117 | }]; 118 | } 119 | 120 | - (void) setHasDoneButton:(BOOL)hasDoneButton 121 | { 122 | [self setHasDoneButton:hasDoneButton animated:NO]; 123 | } 124 | 125 | - (void) setHasDoneButton:(BOOL)hasDoneButton animated:(BOOL)animated 126 | { 127 | if (_hasDoneButton == hasDoneButton) 128 | return; 129 | 130 | [self willChangeValueForKey:@"hasDoneButton"]; 131 | _hasDoneButton = hasDoneButton; 132 | [self didChangeValueForKey:@"hasDoneButton"]; 133 | 134 | NSArray *items; 135 | if (hasDoneButton) 136 | items = [_toolbar.items arrayByAddingObject:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done)]]; 137 | else 138 | items = [_toolbar.items subarrayWithRange:NSMakeRange(0, 2)]; 139 | 140 | [_toolbar setItems:items animated:animated]; 141 | } 142 | 143 | #pragma mark - Actions 144 | 145 | - (void) selectAdjacentResponder:(UISegmentedControl *)sender 146 | { 147 | NSArray *firstResponders = [self.responders filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIResponder *responder, NSDictionary *bindings) { 148 | return [responder isFirstResponder]; 149 | }]]; 150 | UIResponder *firstResponder = [firstResponders lastObject]; 151 | NSInteger offset = sender.selectedSegmentIndex == 0 ? -1 : +1; 152 | NSInteger firstResponderIndex = [self.responders indexOfObject:firstResponder]; 153 | NSInteger adjacentResponderIndex = firstResponderIndex != NSNotFound ? firstResponderIndex + offset : NSNotFound; 154 | UIResponder *adjacentResponder = nil; 155 | if (adjacentResponderIndex >= 0 && adjacentResponderIndex < (NSInteger)[self.responders count]) 156 | adjacentResponder = [self.responders objectAtIndex:adjacentResponderIndex]; 157 | 158 | [adjacentResponder becomeFirstResponder]; 159 | } 160 | 161 | - (void) done 162 | { 163 | [[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil]; 164 | } 165 | 166 | @end 167 | --------------------------------------------------------------------------------