├── .gitignore ├── DemoInPutPasswordView ├── DemoInPutPasswordView.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── DemoInPutPasswordView │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── InputView │ │ ├── LMPopInputPasswordView.h │ │ └── LMPopInputPasswordView.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── DemoInPutPasswordViewTests │ ├── DemoInPutPasswordViewTests.m │ └── Info.plist └── Library │ └── WTReTextField │ ├── WTReParser.h │ ├── WTReParser.m │ ├── WTReTextField.h │ └── WTReTextField.m ├── LICENSE ├── README.md └── input.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | #Pods/ 27 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 459750561B2686C200728D1D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 459750551B2686C200728D1D /* main.m */; }; 11 | 459750591B2686C200728D1D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 459750581B2686C200728D1D /* AppDelegate.m */; }; 12 | 4597505C1B2686C200728D1D /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4597505B1B2686C200728D1D /* ViewController.m */; }; 13 | 4597505F1B2686C200728D1D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4597505D1B2686C200728D1D /* Main.storyboard */; }; 14 | 459750611B2686C200728D1D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 459750601B2686C200728D1D /* Images.xcassets */; }; 15 | 459750641B2686C300728D1D /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 459750621B2686C300728D1D /* LaunchScreen.xib */; }; 16 | 459750701B2686C300728D1D /* DemoInPutPasswordViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4597506F1B2686C300728D1D /* DemoInPutPasswordViewTests.m */; }; 17 | 4597507D1B2687B000728D1D /* LMPopInputPasswordView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4597507C1B2687B000728D1D /* LMPopInputPasswordView.m */; }; 18 | 459750841B26887C00728D1D /* WTReParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 459750811B26887C00728D1D /* WTReParser.m */; }; 19 | 459750851B26887C00728D1D /* WTReTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 459750831B26887C00728D1D /* WTReTextField.m */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXContainerItemProxy section */ 23 | 4597506A1B2686C300728D1D /* PBXContainerItemProxy */ = { 24 | isa = PBXContainerItemProxy; 25 | containerPortal = 459750481B2686C200728D1D /* Project object */; 26 | proxyType = 1; 27 | remoteGlobalIDString = 4597504F1B2686C200728D1D; 28 | remoteInfo = DemoInPutPasswordView; 29 | }; 30 | /* End PBXContainerItemProxy section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 459750501B2686C200728D1D /* DemoInPutPasswordView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DemoInPutPasswordView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 459750541B2686C200728D1D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | 459750551B2686C200728D1D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 36 | 459750571B2686C200728D1D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 37 | 459750581B2686C200728D1D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 38 | 4597505A1B2686C200728D1D /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 39 | 4597505B1B2686C200728D1D /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 40 | 4597505E1B2686C200728D1D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 41 | 459750601B2686C200728D1D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 42 | 459750631B2686C300728D1D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 43 | 459750691B2686C300728D1D /* DemoInPutPasswordViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DemoInPutPasswordViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 4597506E1B2686C300728D1D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | 4597506F1B2686C300728D1D /* DemoInPutPasswordViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DemoInPutPasswordViewTests.m; sourceTree = ""; }; 46 | 4597507B1B2687B000728D1D /* LMPopInputPasswordView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LMPopInputPasswordView.h; sourceTree = ""; }; 47 | 4597507C1B2687B000728D1D /* LMPopInputPasswordView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LMPopInputPasswordView.m; sourceTree = ""; }; 48 | 459750801B26887C00728D1D /* WTReParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WTReParser.h; sourceTree = ""; }; 49 | 459750811B26887C00728D1D /* WTReParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WTReParser.m; sourceTree = ""; }; 50 | 459750821B26887C00728D1D /* WTReTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WTReTextField.h; sourceTree = ""; }; 51 | 459750831B26887C00728D1D /* WTReTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WTReTextField.m; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | 4597504D1B2686C200728D1D /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | 459750661B2686C300728D1D /* Frameworks */ = { 63 | isa = PBXFrameworksBuildPhase; 64 | buildActionMask = 2147483647; 65 | files = ( 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXFrameworksBuildPhase section */ 70 | 71 | /* Begin PBXGroup section */ 72 | 459750471B2686C100728D1D = { 73 | isa = PBXGroup; 74 | children = ( 75 | 4597507E1B26887C00728D1D /* Library */, 76 | 459750521B2686C200728D1D /* DemoInPutPasswordView */, 77 | 4597506C1B2686C300728D1D /* DemoInPutPasswordViewTests */, 78 | 459750511B2686C200728D1D /* Products */, 79 | ); 80 | sourceTree = ""; 81 | }; 82 | 459750511B2686C200728D1D /* Products */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 459750501B2686C200728D1D /* DemoInPutPasswordView.app */, 86 | 459750691B2686C300728D1D /* DemoInPutPasswordViewTests.xctest */, 87 | ); 88 | name = Products; 89 | sourceTree = ""; 90 | }; 91 | 459750521B2686C200728D1D /* DemoInPutPasswordView */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 4597507A1B2687B000728D1D /* InputView */, 95 | 459750571B2686C200728D1D /* AppDelegate.h */, 96 | 459750581B2686C200728D1D /* AppDelegate.m */, 97 | 4597505A1B2686C200728D1D /* ViewController.h */, 98 | 4597505B1B2686C200728D1D /* ViewController.m */, 99 | 4597505D1B2686C200728D1D /* Main.storyboard */, 100 | 459750601B2686C200728D1D /* Images.xcassets */, 101 | 459750621B2686C300728D1D /* LaunchScreen.xib */, 102 | 459750531B2686C200728D1D /* Supporting Files */, 103 | ); 104 | path = DemoInPutPasswordView; 105 | sourceTree = ""; 106 | }; 107 | 459750531B2686C200728D1D /* Supporting Files */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 459750541B2686C200728D1D /* Info.plist */, 111 | 459750551B2686C200728D1D /* main.m */, 112 | ); 113 | name = "Supporting Files"; 114 | sourceTree = ""; 115 | }; 116 | 4597506C1B2686C300728D1D /* DemoInPutPasswordViewTests */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 4597506F1B2686C300728D1D /* DemoInPutPasswordViewTests.m */, 120 | 4597506D1B2686C300728D1D /* Supporting Files */, 121 | ); 122 | path = DemoInPutPasswordViewTests; 123 | sourceTree = ""; 124 | }; 125 | 4597506D1B2686C300728D1D /* Supporting Files */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 4597506E1B2686C300728D1D /* Info.plist */, 129 | ); 130 | name = "Supporting Files"; 131 | sourceTree = ""; 132 | }; 133 | 4597507A1B2687B000728D1D /* InputView */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 4597507B1B2687B000728D1D /* LMPopInputPasswordView.h */, 137 | 4597507C1B2687B000728D1D /* LMPopInputPasswordView.m */, 138 | ); 139 | path = InputView; 140 | sourceTree = ""; 141 | }; 142 | 4597507E1B26887C00728D1D /* Library */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 4597507F1B26887C00728D1D /* WTReTextField */, 146 | ); 147 | path = Library; 148 | sourceTree = ""; 149 | }; 150 | 4597507F1B26887C00728D1D /* WTReTextField */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 459750801B26887C00728D1D /* WTReParser.h */, 154 | 459750811B26887C00728D1D /* WTReParser.m */, 155 | 459750821B26887C00728D1D /* WTReTextField.h */, 156 | 459750831B26887C00728D1D /* WTReTextField.m */, 157 | ); 158 | path = WTReTextField; 159 | sourceTree = ""; 160 | }; 161 | /* End PBXGroup section */ 162 | 163 | /* Begin PBXNativeTarget section */ 164 | 4597504F1B2686C200728D1D /* DemoInPutPasswordView */ = { 165 | isa = PBXNativeTarget; 166 | buildConfigurationList = 459750731B2686C300728D1D /* Build configuration list for PBXNativeTarget "DemoInPutPasswordView" */; 167 | buildPhases = ( 168 | 4597504C1B2686C200728D1D /* Sources */, 169 | 4597504D1B2686C200728D1D /* Frameworks */, 170 | 4597504E1B2686C200728D1D /* Resources */, 171 | ); 172 | buildRules = ( 173 | ); 174 | dependencies = ( 175 | ); 176 | name = DemoInPutPasswordView; 177 | productName = DemoInPutPasswordView; 178 | productReference = 459750501B2686C200728D1D /* DemoInPutPasswordView.app */; 179 | productType = "com.apple.product-type.application"; 180 | }; 181 | 459750681B2686C300728D1D /* DemoInPutPasswordViewTests */ = { 182 | isa = PBXNativeTarget; 183 | buildConfigurationList = 459750761B2686C300728D1D /* Build configuration list for PBXNativeTarget "DemoInPutPasswordViewTests" */; 184 | buildPhases = ( 185 | 459750651B2686C300728D1D /* Sources */, 186 | 459750661B2686C300728D1D /* Frameworks */, 187 | 459750671B2686C300728D1D /* Resources */, 188 | ); 189 | buildRules = ( 190 | ); 191 | dependencies = ( 192 | 4597506B1B2686C300728D1D /* PBXTargetDependency */, 193 | ); 194 | name = DemoInPutPasswordViewTests; 195 | productName = DemoInPutPasswordViewTests; 196 | productReference = 459750691B2686C300728D1D /* DemoInPutPasswordViewTests.xctest */; 197 | productType = "com.apple.product-type.bundle.unit-test"; 198 | }; 199 | /* End PBXNativeTarget section */ 200 | 201 | /* Begin PBXProject section */ 202 | 459750481B2686C200728D1D /* Project object */ = { 203 | isa = PBXProject; 204 | attributes = { 205 | LastUpgradeCheck = 0630; 206 | ORGANIZATIONNAME = YL; 207 | TargetAttributes = { 208 | 4597504F1B2686C200728D1D = { 209 | CreatedOnToolsVersion = 6.3; 210 | }; 211 | 459750681B2686C300728D1D = { 212 | CreatedOnToolsVersion = 6.3; 213 | TestTargetID = 4597504F1B2686C200728D1D; 214 | }; 215 | }; 216 | }; 217 | buildConfigurationList = 4597504B1B2686C200728D1D /* Build configuration list for PBXProject "DemoInPutPasswordView" */; 218 | compatibilityVersion = "Xcode 3.2"; 219 | developmentRegion = English; 220 | hasScannedForEncodings = 0; 221 | knownRegions = ( 222 | en, 223 | Base, 224 | ); 225 | mainGroup = 459750471B2686C100728D1D; 226 | productRefGroup = 459750511B2686C200728D1D /* Products */; 227 | projectDirPath = ""; 228 | projectRoot = ""; 229 | targets = ( 230 | 4597504F1B2686C200728D1D /* DemoInPutPasswordView */, 231 | 459750681B2686C300728D1D /* DemoInPutPasswordViewTests */, 232 | ); 233 | }; 234 | /* End PBXProject section */ 235 | 236 | /* Begin PBXResourcesBuildPhase section */ 237 | 4597504E1B2686C200728D1D /* Resources */ = { 238 | isa = PBXResourcesBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | 4597505F1B2686C200728D1D /* Main.storyboard in Resources */, 242 | 459750641B2686C300728D1D /* LaunchScreen.xib in Resources */, 243 | 459750611B2686C200728D1D /* Images.xcassets in Resources */, 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | }; 247 | 459750671B2686C300728D1D /* Resources */ = { 248 | isa = PBXResourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | /* End PBXResourcesBuildPhase section */ 255 | 256 | /* Begin PBXSourcesBuildPhase section */ 257 | 4597504C1B2686C200728D1D /* Sources */ = { 258 | isa = PBXSourcesBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | 4597505C1B2686C200728D1D /* ViewController.m in Sources */, 262 | 459750851B26887C00728D1D /* WTReTextField.m in Sources */, 263 | 4597507D1B2687B000728D1D /* LMPopInputPasswordView.m in Sources */, 264 | 459750591B2686C200728D1D /* AppDelegate.m in Sources */, 265 | 459750841B26887C00728D1D /* WTReParser.m in Sources */, 266 | 459750561B2686C200728D1D /* main.m in Sources */, 267 | ); 268 | runOnlyForDeploymentPostprocessing = 0; 269 | }; 270 | 459750651B2686C300728D1D /* Sources */ = { 271 | isa = PBXSourcesBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | 459750701B2686C300728D1D /* DemoInPutPasswordViewTests.m in Sources */, 275 | ); 276 | runOnlyForDeploymentPostprocessing = 0; 277 | }; 278 | /* End PBXSourcesBuildPhase section */ 279 | 280 | /* Begin PBXTargetDependency section */ 281 | 4597506B1B2686C300728D1D /* PBXTargetDependency */ = { 282 | isa = PBXTargetDependency; 283 | target = 4597504F1B2686C200728D1D /* DemoInPutPasswordView */; 284 | targetProxy = 4597506A1B2686C300728D1D /* PBXContainerItemProxy */; 285 | }; 286 | /* End PBXTargetDependency section */ 287 | 288 | /* Begin PBXVariantGroup section */ 289 | 4597505D1B2686C200728D1D /* Main.storyboard */ = { 290 | isa = PBXVariantGroup; 291 | children = ( 292 | 4597505E1B2686C200728D1D /* Base */, 293 | ); 294 | name = Main.storyboard; 295 | sourceTree = ""; 296 | }; 297 | 459750621B2686C300728D1D /* LaunchScreen.xib */ = { 298 | isa = PBXVariantGroup; 299 | children = ( 300 | 459750631B2686C300728D1D /* Base */, 301 | ); 302 | name = LaunchScreen.xib; 303 | sourceTree = ""; 304 | }; 305 | /* End PBXVariantGroup section */ 306 | 307 | /* Begin XCBuildConfiguration section */ 308 | 459750711B2686C300728D1D /* Debug */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ALWAYS_SEARCH_USER_PATHS = NO; 312 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 313 | CLANG_CXX_LIBRARY = "libc++"; 314 | CLANG_ENABLE_MODULES = YES; 315 | CLANG_ENABLE_OBJC_ARC = YES; 316 | CLANG_WARN_BOOL_CONVERSION = YES; 317 | CLANG_WARN_CONSTANT_CONVERSION = YES; 318 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 319 | CLANG_WARN_EMPTY_BODY = YES; 320 | CLANG_WARN_ENUM_CONVERSION = YES; 321 | CLANG_WARN_INT_CONVERSION = YES; 322 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 323 | CLANG_WARN_UNREACHABLE_CODE = YES; 324 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 325 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 326 | COPY_PHASE_STRIP = NO; 327 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 328 | ENABLE_STRICT_OBJC_MSGSEND = YES; 329 | GCC_C_LANGUAGE_STANDARD = gnu99; 330 | GCC_DYNAMIC_NO_PIC = NO; 331 | GCC_NO_COMMON_BLOCKS = YES; 332 | GCC_OPTIMIZATION_LEVEL = 0; 333 | GCC_PREPROCESSOR_DEFINITIONS = ( 334 | "DEBUG=1", 335 | "$(inherited)", 336 | ); 337 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 338 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 339 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 340 | GCC_WARN_UNDECLARED_SELECTOR = YES; 341 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 342 | GCC_WARN_UNUSED_FUNCTION = YES; 343 | GCC_WARN_UNUSED_VARIABLE = YES; 344 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 345 | MTL_ENABLE_DEBUG_INFO = YES; 346 | ONLY_ACTIVE_ARCH = YES; 347 | SDKROOT = iphoneos; 348 | }; 349 | name = Debug; 350 | }; 351 | 459750721B2686C300728D1D /* Release */ = { 352 | isa = XCBuildConfiguration; 353 | buildSettings = { 354 | ALWAYS_SEARCH_USER_PATHS = NO; 355 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 356 | CLANG_CXX_LIBRARY = "libc++"; 357 | CLANG_ENABLE_MODULES = YES; 358 | CLANG_ENABLE_OBJC_ARC = YES; 359 | CLANG_WARN_BOOL_CONVERSION = YES; 360 | CLANG_WARN_CONSTANT_CONVERSION = YES; 361 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 362 | CLANG_WARN_EMPTY_BODY = YES; 363 | CLANG_WARN_ENUM_CONVERSION = YES; 364 | CLANG_WARN_INT_CONVERSION = YES; 365 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 366 | CLANG_WARN_UNREACHABLE_CODE = YES; 367 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 368 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 369 | COPY_PHASE_STRIP = NO; 370 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 371 | ENABLE_NS_ASSERTIONS = NO; 372 | ENABLE_STRICT_OBJC_MSGSEND = YES; 373 | GCC_C_LANGUAGE_STANDARD = gnu99; 374 | GCC_NO_COMMON_BLOCKS = YES; 375 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 376 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 377 | GCC_WARN_UNDECLARED_SELECTOR = YES; 378 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 379 | GCC_WARN_UNUSED_FUNCTION = YES; 380 | GCC_WARN_UNUSED_VARIABLE = YES; 381 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 382 | MTL_ENABLE_DEBUG_INFO = NO; 383 | SDKROOT = iphoneos; 384 | VALIDATE_PRODUCT = YES; 385 | }; 386 | name = Release; 387 | }; 388 | 459750741B2686C300728D1D /* Debug */ = { 389 | isa = XCBuildConfiguration; 390 | buildSettings = { 391 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 392 | INFOPLIST_FILE = DemoInPutPasswordView/Info.plist; 393 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 394 | PRODUCT_NAME = "$(TARGET_NAME)"; 395 | }; 396 | name = Debug; 397 | }; 398 | 459750751B2686C300728D1D /* Release */ = { 399 | isa = XCBuildConfiguration; 400 | buildSettings = { 401 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 402 | INFOPLIST_FILE = DemoInPutPasswordView/Info.plist; 403 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 404 | PRODUCT_NAME = "$(TARGET_NAME)"; 405 | }; 406 | name = Release; 407 | }; 408 | 459750771B2686C300728D1D /* Debug */ = { 409 | isa = XCBuildConfiguration; 410 | buildSettings = { 411 | BUNDLE_LOADER = "$(TEST_HOST)"; 412 | FRAMEWORK_SEARCH_PATHS = ( 413 | "$(SDKROOT)/Developer/Library/Frameworks", 414 | "$(inherited)", 415 | ); 416 | GCC_PREPROCESSOR_DEFINITIONS = ( 417 | "DEBUG=1", 418 | "$(inherited)", 419 | ); 420 | INFOPLIST_FILE = DemoInPutPasswordViewTests/Info.plist; 421 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 422 | PRODUCT_NAME = "$(TARGET_NAME)"; 423 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DemoInPutPasswordView.app/DemoInPutPasswordView"; 424 | }; 425 | name = Debug; 426 | }; 427 | 459750781B2686C300728D1D /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | BUNDLE_LOADER = "$(TEST_HOST)"; 431 | FRAMEWORK_SEARCH_PATHS = ( 432 | "$(SDKROOT)/Developer/Library/Frameworks", 433 | "$(inherited)", 434 | ); 435 | INFOPLIST_FILE = DemoInPutPasswordViewTests/Info.plist; 436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 437 | PRODUCT_NAME = "$(TARGET_NAME)"; 438 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DemoInPutPasswordView.app/DemoInPutPasswordView"; 439 | }; 440 | name = Release; 441 | }; 442 | /* End XCBuildConfiguration section */ 443 | 444 | /* Begin XCConfigurationList section */ 445 | 4597504B1B2686C200728D1D /* Build configuration list for PBXProject "DemoInPutPasswordView" */ = { 446 | isa = XCConfigurationList; 447 | buildConfigurations = ( 448 | 459750711B2686C300728D1D /* Debug */, 449 | 459750721B2686C300728D1D /* Release */, 450 | ); 451 | defaultConfigurationIsVisible = 0; 452 | defaultConfigurationName = Release; 453 | }; 454 | 459750731B2686C300728D1D /* Build configuration list for PBXNativeTarget "DemoInPutPasswordView" */ = { 455 | isa = XCConfigurationList; 456 | buildConfigurations = ( 457 | 459750741B2686C300728D1D /* Debug */, 458 | 459750751B2686C300728D1D /* Release */, 459 | ); 460 | defaultConfigurationIsVisible = 0; 461 | }; 462 | 459750761B2686C300728D1D /* Build configuration list for PBXNativeTarget "DemoInPutPasswordViewTests" */ = { 463 | isa = XCConfigurationList; 464 | buildConfigurations = ( 465 | 459750771B2686C300728D1D /* Debug */, 466 | 459750781B2686C300728D1D /* Release */, 467 | ); 468 | defaultConfigurationIsVisible = 0; 469 | }; 470 | /* End XCConfigurationList section */ 471 | }; 472 | rootObject = 459750481B2686C200728D1D /* Project object */; 473 | } 474 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // DemoInPutPasswordView 4 | // 5 | // Created by lqcjdx on 15/6/9. 6 | // Copyright (c) 2015年 YL. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // DemoInPutPasswordView 4 | // 5 | // Created by lqcjdx on 15/6/9. 6 | // Copyright (c) 2015年 YL. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // 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. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 31 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | lm.$(PRODUCT_NAME:rfc1034identifier) 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 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView/InputView/LMPopInputPasswordView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YLPopInputPasswordView.h 3 | // YouLanAgents 4 | // 5 | // Created by lqcjdx on 15/5/27. 6 | // Copyright (c) 2015年 YL. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @protocol LMPopInputPassViewDelegate 13 | 14 | /** 15 | * 委托方法传回点击按钮的索引和输入的文本 16 | * 17 | * @param index 索引0表示取消1表示确认 18 | * @param text 文本框的内容 19 | */ 20 | -(void)buttonClickedAtIndex:(NSUInteger)index withText:(NSString *)text; 21 | 22 | @end 23 | 24 | @interface LMPopInputPasswordView : UIView 25 | @property(nonatomic,assign)iddelegate; 26 | 27 | /** 28 | * 弹出 29 | */ 30 | -(void)pop; 31 | 32 | /** 33 | * 消失 34 | */ 35 | -(void)dismiss; 36 | 37 | @end 38 | 39 | 40 | //禁止复制粘贴的UITextField 41 | #import "WTReTextField.h" 42 | @interface YLPasswordTextFiled : WTReTextField 43 | 44 | @end 45 | /* 46 | 弹出的供输入密码的框 47 | */ -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView/InputView/LMPopInputPasswordView.m: -------------------------------------------------------------------------------- 1 | // 2 | // YLPopInputPasswordView.m 3 | // YouLanAgents 4 | // 5 | // Created by lqcjdx on 15/5/27. 6 | // Copyright (c) 2015年 YL. All rights reserved. 7 | // 8 | 9 | #define kLineTag 1000 10 | #define kDotTag 3000 11 | 12 | #import "LMPopInputPasswordView.h" 13 | #import 14 | 15 | #define kPasswordLength 6 16 | 17 | @interface LMPopInputPasswordView() 18 | { 19 | 20 | } 21 | @property(nonatomic,strong)UIControl *overlayView;//背景 22 | @property(nonatomic,strong)UILabel *titleLabel;//标题 23 | @property(nonatomic,strong)UILabel *lineLabel;//线条 24 | @property(nonatomic,strong)YLPasswordTextFiled *textFiled;//输入文本框 25 | @property(nonatomic,strong)UIButton *cancelButton;//取消按钮 26 | @property(nonatomic,strong)UIButton *ensureButton;//确定按钮 27 | @end 28 | 29 | @implementation LMPopInputPasswordView 30 | 31 | -(instancetype)init{ 32 | if(self = [super init]){ 33 | [self customInit]; 34 | } 35 | return self; 36 | } 37 | 38 | -(void)customInit 39 | { 40 | self.layer.masksToBounds = YES; 41 | self.layer.cornerRadius = 5; 42 | self.backgroundColor = [UIColor groupTableViewBackgroundColor]; 43 | 44 | _titleLabel = [[UILabel alloc]init]; 45 | _titleLabel.backgroundColor = [UIColor clearColor]; 46 | _titleLabel.textAlignment = NSTextAlignmentCenter; 47 | _titleLabel.font = [UIFont systemFontOfSize:15]; 48 | _titleLabel.textColor = [UIColor blackColor]; 49 | _titleLabel.text = @"请输入密码"; 50 | [self addSubview:_titleLabel]; 51 | 52 | _lineLabel = [[UILabel alloc]init]; 53 | _lineLabel.backgroundColor = [UIColor grayColor]; 54 | [self addSubview:_lineLabel]; 55 | 56 | _textFiled = [[YLPasswordTextFiled alloc]init]; 57 | _textFiled.backgroundColor = [UIColor whiteColor]; 58 | _textFiled.layer.masksToBounds = YES; 59 | _textFiled.layer.borderColor = [UIColor grayColor].CGColor; 60 | _textFiled.layer.borderWidth = 1; 61 | _textFiled.layer.cornerRadius = 5; 62 | _textFiled.secureTextEntry = YES; 63 | _textFiled.delegate = self; 64 | _textFiled.tintColor = [UIColor clearColor];//看不到光标 65 | _textFiled.textColor = [UIColor clearColor];//看不到输入内容 66 | _textFiled.font = [UIFont systemFontOfSize:30]; 67 | _textFiled.keyboardType = UIKeyboardTypeNumberPad; 68 | _textFiled.pattern = [NSString stringWithFormat:@"^\\d{%li}$",(long)kPasswordLength]; 69 | [_textFiled addTarget:self action:@selector(textFiledEdingChanged) forControlEvents:UIControlEventEditingChanged]; 70 | [self addSubview:_textFiled]; 71 | 72 | _cancelButton = [UIButton buttonWithType:UIButtonTypeCustom]; 73 | _cancelButton.backgroundColor = [UIColor whiteColor]; 74 | _cancelButton.layer.masksToBounds = YES; 75 | _cancelButton.layer.borderWidth = 1; 76 | _cancelButton.layer.borderColor = [UIColor grayColor].CGColor; 77 | _cancelButton.layer.cornerRadius = 5; 78 | _cancelButton.titleLabel.font = [UIFont systemFontOfSize:16]; 79 | [_cancelButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 80 | [_cancelButton setTitleColor:[[UIColor blackColor]colorWithAlphaComponent:0.7] forState:UIControlStateHighlighted]; 81 | [_cancelButton setTitle:@"取消" forState:UIControlStateNormal]; 82 | [_cancelButton setTitle:@"取消" forState:UIControlStateHighlighted]; 83 | _cancelButton.tag = 0; 84 | [_cancelButton addTarget:self action:@selector(buttonClickedAction:) forControlEvents:UIControlEventTouchUpInside]; 85 | [self addSubview:_cancelButton]; 86 | 87 | _ensureButton = [UIButton buttonWithType:UIButtonTypeCustom]; 88 | _ensureButton.backgroundColor = [UIColor colorWithRed:48/255.0 green:109/255.0 blue:238/255.0 alpha:1]; 89 | _ensureButton.layer.masksToBounds = YES; 90 | _ensureButton.layer.cornerRadius = 5; 91 | _ensureButton.titleLabel.font = [UIFont systemFontOfSize:16]; 92 | [_ensureButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 93 | [_ensureButton setTitleColor:[[UIColor whiteColor]colorWithAlphaComponent:0.7] forState:UIControlStateHighlighted]; 94 | [_ensureButton setTitle:@"确定" forState:UIControlStateNormal]; 95 | [_ensureButton setTitle:@"确定" forState:UIControlStateHighlighted]; 96 | _ensureButton.tag = 1; 97 | [_ensureButton addTarget:self action:@selector(buttonClickedAction:) forControlEvents:UIControlEventTouchUpInside]; 98 | [self addSubview:_ensureButton]; 99 | 100 | _overlayView = [[UIControl alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 101 | _overlayView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]; 102 | [_overlayView addTarget:self 103 | action:@selector(dismiss) 104 | forControlEvents:UIControlEventTouchUpInside]; 105 | } 106 | 107 | -(void)setFrame:(CGRect)frame{ 108 | [super setFrame:frame]; 109 | _overlayView.frame = [[UIScreen mainScreen] bounds]; 110 | 111 | //设置子视图位置 112 | CGFloat offsetX = 10; 113 | CGFloat offsetY = 10; 114 | _titleLabel.frame = CGRectMake(offsetX, offsetY, frame.size.width - 2 * offsetX, 21); 115 | 116 | offsetY += _titleLabel.frame.size.height + 10; 117 | _lineLabel.frame = CGRectMake(offsetX, offsetY, frame.size.width - 2 * offsetX, 1); 118 | 119 | offsetY += _lineLabel.frame.size.height + 10; 120 | _textFiled.frame = CGRectMake(offsetX, offsetY, frame.size.width - 2 * offsetX, 35); 121 | 122 | offsetY += _textFiled.frame.size.height + 10; 123 | CGFloat btnWidth = (frame.size.width - offsetX * 3)/2.0; 124 | _cancelButton.frame = CGRectMake(offsetX, offsetY, btnWidth, 35); 125 | _ensureButton.frame = CGRectMake(offsetX * 2 + btnWidth, offsetY, btnWidth, 35); 126 | } 127 | 128 | #pragma mark ---animation methods 129 | -(void)fadeIn 130 | { 131 | self.transform = CGAffineTransformMakeScale(1.3, 1.3); 132 | self.alpha = 0; 133 | [UIView animateWithDuration:.35 animations:^{ 134 | self.alpha = 1; 135 | self.transform = CGAffineTransformMakeScale(1, 1); 136 | }completion:^(BOOL finished) { 137 | [_textFiled becomeFirstResponder]; 138 | }]; 139 | } 140 | 141 | - (void)fadeOut 142 | { 143 | [self endEditing:YES]; 144 | 145 | [UIView animateWithDuration:.35 animations:^{ 146 | self.transform = CGAffineTransformMakeScale(1.3, 1.3); 147 | self.alpha = 0.0; 148 | } completion:^(BOOL finished) { 149 | if (finished) { 150 | [_overlayView removeFromSuperview]; 151 | [self removeFromSuperview]; 152 | } 153 | }]; 154 | } 155 | 156 | - (void)pop 157 | { 158 | UIWindow *keywindow = [[UIApplication sharedApplication] keyWindow]; 159 | [keywindow addSubview:_overlayView]; 160 | [keywindow addSubview:self]; 161 | 162 | self.center = CGPointMake(keywindow.bounds.size.width/2.0f, 163 | keywindow.bounds.size.height/2.0f-100); 164 | [self fadeIn]; 165 | } 166 | 167 | - (void)dismiss 168 | { 169 | [self fadeOut]; 170 | } 171 | 172 | -(void)buttonClickedAction:(UIButton *)sender 173 | { 174 | //传值给委托对象 175 | if([_delegate respondsToSelector:@selector(buttonClickedAtIndex:withText:)]){ 176 | [_delegate buttonClickedAtIndex:sender.tag withText:_textFiled.text]; 177 | } 178 | 179 | [self dismiss]; 180 | } 181 | 182 | -(void)textFiledEdingChanged 183 | { 184 | NSInteger length = _textFiled.text.length; 185 | NSLog(@"lenght=%li",(long)length); 186 | if(length==kPasswordLength){ 187 | [self buttonClickedAction:_ensureButton]; 188 | } 189 | for(NSInteger i=0;i 10 | 11 | @interface ViewController : UIViewController 12 | @property (strong, nonatomic) IBOutlet UILabel *resultLabel; 13 | 14 | - (IBAction)showInputView:(UIButton *)sender; 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // DemoInPutPasswordView 4 | // 5 | // Created by lqcjdx on 15/6/9. 6 | // Copyright (c) 2015年 YL. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "LMPopInputPasswordView.h" 11 | 12 | @interface ViewController () 13 | { 14 | LMPopInputPasswordView *popView; 15 | } 16 | @end 17 | 18 | @implementation ViewController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | // Do any additional setup after loading the view, typically from a nib. 23 | 24 | [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 25 | [[NSNotificationCenter defaultCenter] addObserver:self 26 | selector:@selector(deviceOrientationDidChange:) 27 | name:UIDeviceOrientationDidChangeNotification 28 | object:nil]; 29 | 30 | 31 | } 32 | 33 | -(void)dealloc{ 34 | [[UIDevice currentDevice]endGeneratingDeviceOrientationNotifications]; 35 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; 36 | } 37 | 38 | - (void)didReceiveMemoryWarning { 39 | [super didReceiveMemoryWarning]; 40 | // Dispose of any resources that can be recreated. 41 | } 42 | 43 | - (IBAction)showInputView:(UIButton *)sender { 44 | _resultLabel.text = nil; 45 | popView = [[LMPopInputPasswordView alloc]init]; 46 | popView.frame = CGRectMake((self.view.frame.size.width - 250)*0.5, 50, 250, 150); 47 | popView.delegate = self; 48 | [popView pop]; 49 | } 50 | 51 | #pragma mark ---LMPopInputPassViewDelegate 52 | -(void)buttonClickedAtIndex:(NSUInteger)index withText:(NSString *)text 53 | { 54 | NSLog(@"buttonIndex = %li password=%@",(long)index,text); 55 | if(index==1){ 56 | if(text.length==0){ 57 | NSLog(@"密码长度不正确"); 58 | }else if(text.length<6){ 59 | NSLog(@"密码长度不正确"); 60 | }else{ 61 | _resultLabel.text = text; 62 | } 63 | } 64 | } 65 | 66 | -(void)deviceOrientationDidChange:(NSObject*)sender{ 67 | UIDevice* device = [sender valueForKey:@"object"]; 68 | if(device.orientation==UIInterfaceOrientationLandscapeLeft||device.orientation==UIInterfaceOrientationLandscapeRight) 69 | { 70 | popView.frame = CGRectMake((self.view.frame.size.width - 250)*0.5, 50, 250, 150); 71 | } 72 | else if(device.orientation==UIInterfaceOrientationPortrait||device.orientation==UIInterfaceOrientationPortraitUpsideDown) 73 | { 74 | popView.frame = CGRectMake((self.view.frame.size.width - 250)*0.5, 50, 250, 150); 75 | } 76 | } 77 | @end 78 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DemoInPutPasswordView 4 | // 5 | // Created by lqcjdx on 15/6/9. 6 | // Copyright (c) 2015年 YL. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordViewTests/DemoInPutPasswordViewTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoInPutPasswordViewTests.m 3 | // DemoInPutPasswordViewTests 4 | // 5 | // Created by lqcjdx on 15/6/9. 6 | // Copyright (c) 2015年 YL. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface DemoInPutPasswordViewTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation DemoInPutPasswordViewTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/DemoInPutPasswordViewTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | yl.$(PRODUCT_NAME:rfc1034identifier) 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 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/Library/WTReTextField/WTReParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // WTReParser.h 3 | // WTReTextField 4 | // 5 | // Created by Alex Skalozub on 5/5/13. 6 | // Copyright (c) 2013 Alex Skalozub. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 9 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | // 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: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | // 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 17 | // IN THE SOFTWARE. 18 | // 19 | 20 | #import 21 | 22 | @class WTReGroup; 23 | 24 | @interface WTReParser : NSObject 25 | { 26 | NSString *_pattern; 27 | BOOL _ignoreCase; 28 | WTReGroup *_node; 29 | BOOL _finished; 30 | NSRegularExpression *_exactQuantifierRegex; 31 | NSRegularExpression *_rangeQuantifierRegex; 32 | } 33 | 34 | - (id)initWithPattern:(NSString*)pattern; 35 | - (id)initWithPattern:(NSString*)pattern ignoreCase:(BOOL)ignoreCase; 36 | - (NSString*)reformatString:(NSString*)input; 37 | 38 | @property (readonly, nonatomic) NSString *pattern; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/Library/WTReTextField/WTReParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // WTReParser.m 3 | // WTReTextField 4 | // 5 | // Created by Alex Skalozub on 5/5/13. 6 | // Copyright (c) 2013 Alex Skalozub. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 9 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | // 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: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | // 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 17 | // IN THE SOFTWARE. 18 | // 19 | 20 | #import "WTReParser.h" 21 | 22 | // common interface for all node types 23 | 24 | @interface WTReNode : NSObject 25 | 26 | @property (assign, nonatomic) NSRange sourceRange; 27 | @property (weak, nonatomic) WTReNode *parent; 28 | @property (weak, nonatomic) WTReNode *nextSibling; 29 | 30 | - (NSString*)displayString:(NSString*)pattern; 31 | 32 | @end 33 | 34 | @implementation WTReNode 35 | 36 | - (NSString*)displayString:(NSString*)pattern 37 | { 38 | return [pattern substringWithRange:_sourceRange]; 39 | } 40 | 41 | @end 42 | 43 | // interface for group node 44 | 45 | @interface WTReGroup : WTReNode 46 | 47 | @property (assign, nonatomic) BOOL capturing; 48 | @property (strong, nonatomic) NSArray *children; 49 | 50 | @end 51 | 52 | @implementation WTReGroup 53 | 54 | - (void)dealloc 55 | { 56 | _children = nil; 57 | } 58 | 59 | - (NSString*)displayString:(NSString*)pattern 60 | { 61 | return [NSString stringWithFormat:@"(%@)", [pattern substringWithRange:self.sourceRange]]; 62 | } 63 | 64 | - (NSString*)debugDescription 65 | { 66 | if (_capturing) 67 | return @"Capturing Parentheses"; 68 | else 69 | return @"Non-capturing Parentheses"; 70 | } 71 | 72 | @end 73 | 74 | // interface for alternation node 75 | 76 | @interface WTReAlternation : WTReNode 77 | 78 | @property (strong, nonatomic) NSArray *children; 79 | 80 | @end 81 | 82 | @implementation WTReAlternation 83 | 84 | - (void)dealloc 85 | { 86 | _children = nil; 87 | } 88 | 89 | - (NSString*)displayString:(NSString*)pattern 90 | { 91 | return [pattern substringWithRange:self.sourceRange]; 92 | } 93 | 94 | - (NSString*)debugDescription 95 | { 96 | return @"Alternation"; 97 | } 98 | 99 | @end 100 | 101 | // interface for quantifier 102 | 103 | @interface WTReQuantifier : WTReNode 104 | 105 | - (id)initWithFrom:(NSUInteger)from to:(NSUInteger)to; 106 | 107 | @property (strong, nonatomic) WTReNode *child; 108 | @property (assign, nonatomic) BOOL greedy; 109 | @property (assign, nonatomic) NSUInteger countFrom; 110 | @property (assign, nonatomic) NSUInteger countTo; 111 | 112 | @end 113 | 114 | @implementation WTReQuantifier 115 | 116 | - (id)init 117 | { 118 | self = [super init]; 119 | if (self) 120 | { 121 | _greedy = YES; 122 | _countFrom = 1; 123 | _countTo = 1; 124 | } 125 | return self; 126 | } 127 | 128 | - (id)initWithFrom:(NSUInteger)from to:(NSUInteger)to 129 | { 130 | self = [super init]; 131 | if (self) 132 | { 133 | _greedy = YES; 134 | _countFrom = from; 135 | _countTo = to; 136 | } 137 | return self; 138 | } 139 | 140 | - (void)dealloc 141 | { 142 | _child = nil; 143 | } 144 | 145 | - (NSString*)debugDescription 146 | { 147 | if (_greedy) 148 | return @"Greedy Quantifier"; 149 | else 150 | return @"Lazy Quantifier"; 151 | } 152 | 153 | - (NSString*)displayQuantifier 154 | { 155 | NSString *pat = nil; 156 | if (_countFrom == 0) { 157 | if (_countTo == NSUIntegerMax) { 158 | pat = @"*"; 159 | } else if (_countTo == 1) { 160 | pat = @"?"; 161 | } else { 162 | pat = [NSString stringWithFormat:@"{,%lu}", (unsigned long)_countTo]; 163 | } 164 | } else if (_countFrom == 1 && _countTo == NSUIntegerMax) { 165 | pat = @"+"; 166 | } else if (_countFrom == _countTo) { 167 | pat = [NSString stringWithFormat:@"{%lu}", (unsigned long)_countFrom]; 168 | } else if (_countTo == NSUIntegerMax) { 169 | pat = [NSString stringWithFormat:@"{%lu,}", (unsigned long)_countFrom]; 170 | } else { 171 | pat = [NSString stringWithFormat:@"{%lu,%lu}", (unsigned long)_countFrom, (unsigned long)_countTo]; 172 | } 173 | 174 | if (_greedy) return pat; 175 | 176 | return [pat stringByAppendingString:@"?"]; 177 | } 178 | 179 | - (NSString*)displayString:(NSString *)pattern 180 | { 181 | return [[_child displayString:pattern] stringByAppendingString:[self displayQuantifier]]; 182 | } 183 | 184 | @end 185 | 186 | // base interface for all character subsets 187 | 188 | @interface WTReCharacterBase : WTReNode 189 | 190 | @property (assign, nonatomic) BOOL ignoreCase; 191 | 192 | - (BOOL)matchesCharacter:(unichar)c; 193 | 194 | @end 195 | 196 | @implementation WTReCharacterBase 197 | 198 | - (BOOL)matchesCharacter:(unichar)c 199 | { 200 | @throw [NSException exceptionWithName:@"Invalid operation" reason:@"Override this method in subclasses" userInfo:nil]; 201 | } 202 | 203 | @end 204 | 205 | // interface for character set node 206 | 207 | @interface WTReCharacterSet : WTReCharacterBase 208 | 209 | @property (assign, nonatomic) BOOL negation; 210 | @property (strong, nonatomic) NSCharacterSet *chars; 211 | 212 | @end 213 | 214 | @implementation WTReCharacterSet 215 | 216 | - (BOOL)matchesCharacter:(unichar)c 217 | { 218 | BOOL contains = [_chars characterIsMember:c]; 219 | 220 | if (!contains && self.ignoreCase) 221 | { 222 | if ([[NSCharacterSet lowercaseLetterCharacterSet] characterIsMember:c]) 223 | { 224 | // test upper 225 | unichar uc = [[[NSString stringWithCharacters:&c length:1] uppercaseString] characterAtIndex: 0]; 226 | contains = [_chars characterIsMember:uc]; 227 | } 228 | else if ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:c]) 229 | { 230 | // test lower 231 | unichar lc = [[[NSString stringWithCharacters:&c length:1] lowercaseString] characterAtIndex: 0]; 232 | contains = [_chars characterIsMember:lc]; 233 | } 234 | } 235 | 236 | return contains ^ _negation; 237 | } 238 | 239 | - (NSString*)displayString:(NSString*)pattern 240 | { 241 | return [NSString stringWithFormat:@"[%@]", [pattern substringWithRange:self.sourceRange]]; 242 | } 243 | 244 | - (NSString*)debugDescription 245 | { 246 | return @"Character Class"; 247 | } 248 | 249 | @end 250 | 251 | // interface for literal node 252 | 253 | @interface WTReLiteral : WTReCharacterBase 254 | 255 | @property (assign, nonatomic) unichar character; 256 | 257 | @end 258 | 259 | @implementation WTReLiteral 260 | 261 | - (BOOL)matchesCharacter:(unichar)c 262 | { 263 | BOOL contains = _character == c; 264 | 265 | if (!contains && self.ignoreCase) 266 | { 267 | if ([[NSCharacterSet lowercaseLetterCharacterSet] characterIsMember:c]) 268 | { 269 | // test upper 270 | unichar uc = [[[NSString stringWithCharacters:&c length:1] uppercaseString] characterAtIndex: 0]; 271 | contains = _character == uc; 272 | } 273 | else if ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:c]) 274 | { 275 | // test lower 276 | unichar lc = [[[NSString stringWithCharacters:&c length:1] lowercaseString] characterAtIndex: 0]; 277 | contains = _character == lc; 278 | } 279 | } 280 | 281 | return contains; 282 | } 283 | 284 | - (NSString*)displayString:(NSString *)pattern 285 | { 286 | return [NSString stringWithFormat:@"'%c'", _character]; 287 | } 288 | 289 | - (NSString*)debugDescription 290 | { 291 | return @"Character"; 292 | } 293 | 294 | @end 295 | 296 | // interface for any character (.) node 297 | 298 | @interface WTReAnyCharacter : WTReCharacterBase 299 | 300 | @end 301 | 302 | @implementation WTReAnyCharacter 303 | 304 | - (BOOL)matchesCharacter:(unichar)c 305 | { 306 | return YES; 307 | } 308 | 309 | - (NSString*)displayString:(NSString*)pattern 310 | { 311 | return @"."; 312 | } 313 | 314 | - (NSString*)debugDescription 315 | { 316 | return @"Any Character"; 317 | } 318 | 319 | @end 320 | 321 | // interface for end of string ($) node 322 | 323 | @interface WTReEndOfString : WTReCharacterBase 324 | 325 | @end 326 | 327 | @implementation WTReEndOfString 328 | 329 | - (NSString*)displayString:(NSString *)pattern 330 | { 331 | return @"$"; 332 | } 333 | 334 | - (NSString*)debugDescription 335 | { 336 | return @"End of String"; 337 | } 338 | 339 | - (BOOL)matchesCharacter:(unichar)c 340 | { 341 | return c == 0; 342 | } 343 | 344 | @end 345 | 346 | // helper internal classes 347 | 348 | @interface WTState : NSObject 349 | { 350 | NSMutableArray *_transitions; 351 | } 352 | 353 | @property (assign, nonatomic) BOOL isFinal; 354 | @property (readonly, nonatomic) NSMutableArray *transitions; 355 | 356 | @end 357 | 358 | @implementation WTState 359 | 360 | - (NSMutableArray*)transitions 361 | { 362 | if (_transitions == nil) 363 | _transitions = [[NSMutableArray alloc] initWithCapacity:1]; 364 | return _transitions; 365 | } 366 | 367 | @end 368 | 369 | @interface WTTransition : NSObject 370 | 371 | @property (weak, nonatomic) WTReCharacterBase *node; 372 | @property (weak, nonatomic) WTReLiteral *bypassNode; 373 | @property (strong, nonatomic) WTState *nextState; 374 | 375 | @end 376 | 377 | @implementation WTTransition 378 | 379 | @end 380 | 381 | // parser implementation 382 | 383 | @implementation WTReParser 384 | 385 | - (id)initWithPattern:(NSString *)pattern 386 | { 387 | return [self initWithPattern:pattern ignoreCase:NO]; 388 | } 389 | 390 | - (id)initWithPattern:(NSString *)pattern ignoreCase:(BOOL)ignoreCase 391 | { 392 | NSParameterAssert(pattern != nil && ![pattern isEqualToString:@""]); 393 | 394 | self = [super init]; 395 | if (self) 396 | { 397 | _pattern = pattern; 398 | _ignoreCase = ignoreCase; 399 | _node = nil; 400 | [self parsePattern]; 401 | } 402 | return self; 403 | } 404 | 405 | - (void)dealloc 406 | { 407 | _pattern = nil; 408 | _node = nil; 409 | _exactQuantifierRegex = nil; 410 | _rangeQuantifierRegex = nil; 411 | } 412 | 413 | #ifdef DEBUG 414 | 415 | - (NSString*)debugDescription 416 | { 417 | return [self nodeDescription:_node withLevel:0]; 418 | } 419 | 420 | - (NSString*)nodeDescription:(WTReNode*)node withLevel:(NSUInteger)level 421 | { 422 | NSMutableString *buffer = [[NSMutableString alloc] initWithCapacity:100]; 423 | 424 | for (NSUInteger i = 0; i < level; i++) 425 | [buffer appendString:@" "]; 426 | 427 | [buffer appendString:[node displayString:_pattern]]; 428 | [buffer appendString:@" - "]; 429 | [buffer appendString:[node debugDescription]]; 430 | [buffer appendString:@"\n"]; 431 | 432 | if ([node isKindOfClass:[WTReAlternation class]]) 433 | { 434 | for (WTReNode* c in [(WTReAlternation*)node children]) 435 | [buffer appendString:[self nodeDescription:c withLevel:level+1]]; 436 | } 437 | else if ([node isKindOfClass:[WTReGroup class]]) 438 | { 439 | for (WTReNode* c in [(WTReGroup*)node children]) 440 | [buffer appendString:[self nodeDescription:c withLevel:level+1]]; 441 | } 442 | else if ([node isKindOfClass:[WTReQuantifier class]]) 443 | { 444 | [buffer appendString:[self nodeDescription:[(WTReQuantifier*)node child] withLevel:level+1]]; 445 | } 446 | 447 | return buffer; 448 | } 449 | 450 | #endif 451 | 452 | - (void)parsePattern 453 | { 454 | if (_node != nil) return; 455 | 456 | if (![_pattern hasPrefix:@"^"]) 457 | @throw [NSException exceptionWithName:@"Error" reason:@"Invalid pattern start" userInfo:nil]; 458 | 459 | _finished = NO; 460 | _exactQuantifierRegex = [[NSRegularExpression alloc] initWithPattern:@"^\\{\\s*(\\d+)\\s*\\}$" options:0 error:nil]; 461 | _rangeQuantifierRegex = [[NSRegularExpression alloc] initWithPattern:@"^\\{\\s*(\\d*)\\s*,\\s*(\\d*)\\s*\\}$" options:0 error:nil]; 462 | 463 | _node = [self parseSubpattern:_pattern inRange:NSMakeRange(1, _pattern.length - 1) enclosed:NO]; 464 | 465 | _exactQuantifierRegex = nil; 466 | _rangeQuantifierRegex = nil; 467 | 468 | if (!_finished) 469 | @throw [NSException exceptionWithName:@"Error" reason:@"Invalid pattern end" userInfo:nil]; 470 | } 471 | 472 | - (BOOL)isValidEscapedChar:(unichar)c inCharset:(BOOL)inCharset 473 | { 474 | switch (c) 475 | { 476 | case '(': 477 | case ')': 478 | case '[': 479 | case ']': 480 | case '{': 481 | case '}': 482 | case '\\': 483 | case '|': 484 | case 'd': 485 | case 'D': 486 | case 'w': 487 | case 'W': 488 | case 's': 489 | case 'S': 490 | case 'u': 491 | case '\'': 492 | case '.': 493 | case '+': 494 | case '*': 495 | case '?': 496 | case '$': 497 | case '^': 498 | return YES; 499 | 500 | case '-': 501 | return inCharset; 502 | 503 | default: 504 | return NO; 505 | } 506 | } 507 | 508 | - (void)raiseParserError:(NSString*)error atPos:(NSUInteger)pos 509 | { 510 | NSString *pat = [NSString stringWithFormat:@"%@ \u25B6%@", [_pattern substringToIndex:pos], [_pattern substringFromIndex:pos]]; 511 | @throw [NSException exceptionWithName:@"Parse error" reason:[NSString stringWithFormat:@"%@ @ pos %lu: %@", error, (unsigned long)pos, pat] userInfo:nil]; 512 | } 513 | 514 | - (WTReCharacterBase*)parseCharset:(NSString*)pattern inRange:(NSRange)range enclosed:(BOOL)enclosed 515 | { 516 | BOOL negation = NO; 517 | NSUInteger count = 0; 518 | unichar lastChar = 0; 519 | NSMutableCharacterSet *chars = [[NSMutableCharacterSet alloc] init]; 520 | BOOL escape = NO; 521 | 522 | for (NSUInteger i = 0; i < range.length; i++) { 523 | unichar c = [pattern characterAtIndex:(range.location + i)]; 524 | 525 | if (enclosed && i == 0 && c == '^') { 526 | negation = YES; 527 | continue; 528 | } 529 | 530 | if (c == '\\' && !escape) { 531 | escape = YES; 532 | continue; 533 | } 534 | 535 | if (escape) { 536 | // process character classes and escaped special chars 537 | 538 | if (![self isValidEscapedChar:c inCharset:enclosed]) 539 | [self raiseParserError:@"Invalid escape sequence" atPos:(range.location + i)]; 540 | 541 | if (c == 'd') { 542 | [chars formUnionWithCharacterSet:[NSCharacterSet decimalDigitCharacterSet]]; 543 | count += 2; 544 | } 545 | else if (c == 'D') { 546 | [chars formUnionWithCharacterSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]; 547 | count += 2; 548 | } 549 | else if (c == 'w') { 550 | [chars formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]]; 551 | count += 2; 552 | } 553 | else if (c == 'W') { 554 | [chars formUnionWithCharacterSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]]; 555 | count += 2; 556 | } 557 | else if (c == 's') { 558 | [chars formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]]; 559 | count += 2; 560 | } 561 | else if (c == 'S') { 562 | [chars formUnionWithCharacterSet:[[NSCharacterSet whitespaceCharacterSet] invertedSet]]; 563 | count += 2; 564 | } 565 | else if (c == 'u') { 566 | // unicode character in format \uFFFF 567 | 568 | if (i + 4 >= range.length) 569 | [self raiseParserError:@"Expected a four-digit hexadecimal character code" atPos:(range.location + i + 1)]; 570 | 571 | NSScanner *scanner = [NSScanner scannerWithString:[pattern substringWithRange:NSMakeRange(range.location + i + 1, 4)]]; 572 | 573 | unsigned int code; 574 | if (![scanner scanHexInt:&code]) 575 | [self raiseParserError:@"Expected a four-digit hexadecimal character code" atPos:(range.location + i + 1)]; 576 | 577 | lastChar = (unichar)code; 578 | [chars addCharactersInRange:NSMakeRange(lastChar, 1)]; 579 | i += 4; 580 | count++; 581 | } 582 | else { 583 | // todo: check for other escape sequences 584 | 585 | [chars addCharactersInRange:NSMakeRange(c, 1)]; 586 | lastChar = c; 587 | count++; 588 | } 589 | 590 | escape = NO; 591 | } 592 | else if (enclosed && c == '-' && i > 0 && i < range.length - 1) { 593 | // process character range 594 | 595 | unichar rangeStart = [pattern characterAtIndex:(range.location + i - 1)]; 596 | unichar rangeEnd = [pattern characterAtIndex:(range.location + i + 1)]; 597 | 598 | if (rangeEnd < rangeStart) 599 | [self raiseParserError:@"Invalid character range" atPos:(range.location + i - 1)]; 600 | 601 | NSCharacterSet *alphanum = [NSCharacterSet alphanumericCharacterSet]; 602 | if (![alphanum characterIsMember:rangeStart] || ![alphanum characterIsMember:rangeEnd]) 603 | [self raiseParserError:@"Invalid character range" atPos:(range.location + i - 1)]; 604 | 605 | // iOS5 has a bug: things go ugly if range intersects with existing one, so exclude it first 606 | [chars removeCharactersInRange:NSMakeRange(rangeStart, rangeEnd - rangeStart + 1)]; 607 | [chars addCharactersInRange:NSMakeRange(rangeStart, rangeEnd - rangeStart + 1)]; 608 | i++; 609 | count += 2; 610 | } 611 | else { 612 | // process simple char 613 | 614 | [chars addCharactersInRange:NSMakeRange(c, 1)]; 615 | lastChar = c; 616 | count++; 617 | } 618 | } 619 | 620 | if (!negation && count == 1) { 621 | WTReLiteral *l = [[WTReLiteral alloc] init]; 622 | l.character = lastChar; 623 | l.sourceRange = range; 624 | l.ignoreCase = _ignoreCase; 625 | return l; 626 | } else { 627 | WTReCharacterSet *s = [[WTReCharacterSet alloc] init]; 628 | s.negation = negation; 629 | s.chars = chars; 630 | s.sourceRange = range; 631 | s.ignoreCase = _ignoreCase; 632 | return s; 633 | } 634 | } 635 | 636 | - (WTReGroup*)groupFromNodes:(NSArray*)nodes enclosed:(BOOL)enclosed 637 | { 638 | if (nodes.count == 1) { 639 | WTReGroup *t = [nodes objectAtIndex:0]; 640 | if ([t isKindOfClass:[WTReGroup class]]) { 641 | t.capturing |= enclosed; 642 | return t; 643 | } 644 | } 645 | 646 | WTReGroup *g = [[WTReGroup alloc] init]; 647 | g.children = [nodes copy]; 648 | g.capturing = enclosed; 649 | 650 | // setup links 651 | WTReNode *prev = [g.children objectAtIndex:0]; 652 | prev.parent = g; 653 | 654 | for (NSUInteger i = 1; i < g.children.count; i++) { 655 | WTReNode *curr = [g.children objectAtIndex:i]; 656 | curr.parent = g; 657 | prev.nextSibling = curr; 658 | prev = curr; 659 | } 660 | 661 | return g; 662 | } 663 | 664 | - (WTReGroup*)parseSubpattern:(NSString*)pattern inRange:(NSRange)range enclosed:(BOOL)enclosed 665 | { 666 | NSMutableArray *nodes = [[NSMutableArray alloc] initWithCapacity:range.length]; 667 | 668 | NSMutableArray *alternations = nil; 669 | NSUInteger startPos = 0, endPos = range.length; 670 | 671 | BOOL escape = NO; 672 | WTReNode *lastnode = nil; 673 | 674 | for (NSUInteger i = 0; i < range.length; i++) { 675 | if (_finished) 676 | [self raiseParserError:@"Found pattern end in the middle of string" atPos:(range.location + i)]; 677 | 678 | unichar c = [pattern characterAtIndex:(range.location + i)]; 679 | 680 | if (enclosed && i == 0 && c == '?') { 681 | // group modifiers are present 682 | 683 | if (range.length < 3) 684 | [self raiseParserError:@"Invalid group found in pattern" atPos:(range.location + i)]; 685 | 686 | NSCharacterSet *alphanum = [NSCharacterSet alphanumericCharacterSet]; 687 | 688 | unichar d = [pattern characterAtIndex:(range.location + i + 1)]; 689 | if (d == '<') { 690 | // tagged group (?…) 691 | for (NSUInteger j = i + 2; j < range.length; j++) { 692 | unichar d = [pattern characterAtIndex:(range.location + j)]; 693 | 694 | if (d == '<') { 695 | [self raiseParserError:@"Invalid group tag found in pattern" atPos:(range.location + j)]; 696 | } else if (d == '>') { 697 | if (j == i + 2) 698 | [self raiseParserError:@"Empty group tag found in pattern" atPos:(range.location + j)]; 699 | i = j; 700 | break; 701 | } else if (![alphanum characterIsMember:d]) { 702 | [self raiseParserError:@"Group tag contains invalid chars" atPos:(range.location + j)]; 703 | } 704 | } 705 | } 706 | else if (d == '\'') { 707 | // tagged group (?'style2'…) 708 | for (NSUInteger j = i + 2; j < range.length; j++) { 709 | unichar d = [pattern characterAtIndex:(range.location + j)]; 710 | 711 | if (d == '\'') { 712 | if (j == i + 2) 713 | [self raiseParserError:@"Empty group tag found in pattern" atPos:(range.location + j)]; 714 | i = j; 715 | break; 716 | } else if (![alphanum characterIsMember:d]) { 717 | [self raiseParserError:@"Group tag contains invalid chars" atPos:(range.location + j)]; 718 | } 719 | } 720 | } 721 | else if (d == ':') { 722 | // non-capturing group 723 | enclosed = FALSE; 724 | i++; 725 | } 726 | else { 727 | [self raiseParserError:@"Unknown group modifier" atPos:(range.location + i + 1)]; 728 | } 729 | 730 | continue; 731 | } 732 | 733 | if (c == '\\' && !escape) { 734 | escape = YES; 735 | continue; 736 | } 737 | 738 | if (escape) { 739 | if (![self isValidEscapedChar:c inCharset:NO] || i == 0) 740 | [self raiseParserError:@"Invalid escape sequence" atPos:(range.location + i)]; 741 | 742 | lastnode = [self parseCharset:pattern inRange:NSMakeRange(range.location + i - 1, 2) enclosed:NO]; 743 | [nodes addObject:lastnode]; 744 | 745 | escape = NO; 746 | } 747 | else if (c == '(') { 748 | NSInteger brackets = 1; 749 | BOOL escape2 = NO; 750 | 751 | for (NSUInteger j = i + 1; j < range.length; j++) { 752 | unichar d = [pattern characterAtIndex:(range.location + j)]; 753 | 754 | if (escape2) { 755 | escape2 = NO; 756 | } else if (d == '\\') { 757 | escape2 = YES; 758 | } else if (d == '(') { 759 | brackets++; 760 | } else if (d == ')') { 761 | brackets--; 762 | 763 | if (brackets == 0) { 764 | lastnode = [self parseSubpattern:pattern inRange:NSMakeRange(range.location + i + 1, j - i - 1) enclosed:YES]; 765 | [nodes addObject:lastnode]; 766 | 767 | i = j; 768 | break; 769 | } 770 | } 771 | } 772 | 773 | if (brackets != 0) 774 | [self raiseParserError:@"Unclosed group bracket" atPos:(range.location + i)]; 775 | } 776 | else if (c == ')') { 777 | [self raiseParserError:@"Unopened group bracket" atPos:(range.location + i)]; 778 | } 779 | else if (c == '[') { 780 | BOOL escape2 = NO; 781 | BOOL valid = NO; 782 | 783 | for (NSUInteger j = i + 1; j < range.length; j++) { 784 | unichar d = [pattern characterAtIndex:(range.location + j)]; 785 | 786 | if (escape2) { 787 | escape2 = NO; 788 | } else if (d == '\\') { 789 | escape2 = YES; 790 | } else if (d == '[' || d == '(' || d == ')') { 791 | // invalid character 792 | break; 793 | } else if (d == ']') { 794 | lastnode = [self parseCharset:pattern inRange:NSMakeRange(range.location + i + 1, j - i - 1) enclosed:YES]; 795 | [nodes addObject:lastnode]; 796 | 797 | i = j; 798 | valid = YES; 799 | break; 800 | } 801 | } 802 | 803 | if (!valid) 804 | [self raiseParserError:@"Unclosed character set bracket" atPos:(range.location + i)]; 805 | } 806 | else if (c == ']') { 807 | [self raiseParserError:@"Unopened character set bracket" atPos:(range.location + i)]; 808 | } 809 | else if (c == '{') { 810 | if (lastnode == nil || [lastnode isKindOfClass:[WTReQuantifier class]]) 811 | [self raiseParserError:@"Invalid quantifier usage" atPos:(range.location + i)]; 812 | 813 | BOOL valid = NO; 814 | 815 | for (NSUInteger j = i + 1; j < range.length; j++) { 816 | unichar d = [pattern characterAtIndex:(range.location + j)]; 817 | 818 | if (d == '}') { 819 | NSString *from, *to; 820 | 821 | NSTextCheckingResult *m = [_exactQuantifierRegex firstMatchInString:pattern options:0 range:NSMakeRange(range.location + i, j - i + 1)]; 822 | if (m != nil) { 823 | from = [pattern substringWithRange:[m rangeAtIndex:1]]; 824 | to = from; 825 | } else { 826 | m = [_rangeQuantifierRegex firstMatchInString:pattern options:0 range:NSMakeRange(range.location + i, j - i + 1)]; 827 | if (m == nil) 828 | [self raiseParserError:@"Invalid quantifier format" atPos:(range.location + i)]; 829 | 830 | from = [pattern substringWithRange:[m rangeAtIndex:1]]; 831 | to = [pattern substringWithRange:[m rangeAtIndex:2]]; 832 | } 833 | 834 | WTReQuantifier *qtf = [[WTReQuantifier alloc] init]; 835 | 836 | if (from == nil || [from isEqualToString:@""]) 837 | qtf.countFrom = 0; 838 | else 839 | qtf.countFrom = [from integerValue]; 840 | 841 | if (to == nil || [to isEqualToString:@""]) 842 | qtf.countTo = NSUIntegerMax; 843 | else 844 | qtf.countTo = [to integerValue]; 845 | 846 | if (qtf.countFrom > qtf.countTo) 847 | [self raiseParserError:@"Invalid quantifier range" atPos:(range.location + i)]; 848 | 849 | [nodes removeLastObject]; 850 | qtf.child = lastnode; 851 | lastnode.parent = qtf; 852 | lastnode = qtf; 853 | [nodes addObject:lastnode]; 854 | 855 | i = j; 856 | valid = YES; 857 | break; 858 | } 859 | } 860 | 861 | if (!valid) 862 | [self raiseParserError:@"Unclosed quantifier bracket" atPos:(range.location + i)]; 863 | } 864 | else if (c == '}') { 865 | [self raiseParserError:@"Unopened qualifier bracket" atPos:(range.location + i)]; 866 | } 867 | else if (c == '*') { 868 | if (lastnode == nil || [lastnode isKindOfClass:[WTReQuantifier class]]) 869 | [self raiseParserError:@"Invalid quantifier usage" atPos:(range.location + i)]; 870 | 871 | [nodes removeLastObject]; 872 | WTReQuantifier *qtf = [[WTReQuantifier alloc] initWithFrom:0 to:NSUIntegerMax]; 873 | qtf.child = lastnode; 874 | lastnode.parent = qtf; 875 | lastnode = qtf; 876 | [nodes addObject:lastnode]; 877 | } 878 | else if (c == '+') { 879 | if (lastnode == nil || [lastnode isKindOfClass:[WTReQuantifier class]]) 880 | [self raiseParserError:@"Invalid quantifier usage" atPos:(range.location + i)]; 881 | 882 | [nodes removeLastObject]; 883 | WTReQuantifier *qtf = [[WTReQuantifier alloc] initWithFrom:1 to:NSUIntegerMax]; 884 | qtf.child = lastnode; 885 | lastnode.parent = qtf; 886 | lastnode = qtf; 887 | [nodes addObject:lastnode]; 888 | } 889 | else if (c == '?') { 890 | if (lastnode == nil) 891 | [self raiseParserError:@"Invalid quantifier usage" atPos:(range.location + i)]; 892 | 893 | if ([lastnode isKindOfClass:[WTReQuantifier class]]) { 894 | // greediness modifier 895 | [(WTReQuantifier*)lastnode setGreedy:NO]; 896 | } else { 897 | [nodes removeLastObject]; 898 | WTReQuantifier *qtf = [[WTReQuantifier alloc] initWithFrom:0 to:1]; 899 | qtf.child = lastnode; 900 | lastnode.parent = qtf; 901 | lastnode = qtf; 902 | [nodes addObject:lastnode]; 903 | } 904 | 905 | lastnode = nil; 906 | } 907 | else if (c == '.') { 908 | // any character 909 | lastnode = [[WTReAnyCharacter alloc] init]; 910 | [nodes addObject:lastnode]; 911 | } 912 | else if (c == '|') { 913 | // alternation 914 | if (alternations == nil) 915 | alternations = [[NSMutableArray alloc] initWithCapacity:2]; 916 | 917 | WTReGroup *g = [self groupFromNodes:nodes enclosed:enclosed]; 918 | g.sourceRange = NSMakeRange(range.location + startPos, i - startPos); 919 | startPos = i + 1; 920 | 921 | [alternations addObject:g]; 922 | [nodes removeAllObjects]; 923 | lastnode = nil; 924 | } 925 | else if (c == '$') { 926 | if (alternations != nil && enclosed) 927 | [self raiseParserError:@"End of string shouldn't be inside alternation" atPos:(range.location + i)]; 928 | 929 | if (range.location + i + 1 < pattern.length) 930 | [self raiseParserError:@"Unexpected end of string" atPos:(range.location + i + 1)]; 931 | 932 | lastnode = [[WTReEndOfString alloc] init]; 933 | [nodes addObject:lastnode]; 934 | 935 | endPos = i + 1; 936 | _finished = YES; 937 | break; 938 | } 939 | else { 940 | lastnode = [self parseCharset:pattern inRange:NSMakeRange(range.location + i, 1) enclosed:NO]; 941 | [nodes addObject:lastnode]; 942 | } 943 | } 944 | 945 | if (escape) 946 | [self raiseParserError:@"Invalid group ending" atPos:(range.location + range.length)]; 947 | 948 | NSUInteger endPosForGroup = endPos; 949 | if (alternations != nil && _finished && !enclosed) 950 | { 951 | // root-level alternation not included in parenthesis: 952 | // ^aaa|bbb$ 953 | // need to strip end-of-string node from last group 954 | [nodes removeLastObject]; 955 | // and decrement last alternation length by 1 956 | endPosForGroup--; 957 | } 958 | 959 | WTReGroup *g = [self groupFromNodes:nodes enclosed:enclosed]; 960 | g.sourceRange = NSMakeRange(range.location + startPos, endPosForGroup - startPos); 961 | g.capturing = enclosed; 962 | 963 | if (alternations != nil) { 964 | // build alternation and enclose it into group 965 | [alternations addObject:g]; 966 | 967 | WTReAlternation *a = [[WTReAlternation alloc] init]; 968 | a.children = alternations; 969 | a.sourceRange = NSMakeRange(range.location, endPos); 970 | 971 | // setup links 972 | WTReNode *prev = [alternations objectAtIndex:0]; 973 | prev.parent = a; 974 | 975 | for (NSUInteger i = 1; i < alternations.count; i++) { 976 | WTReNode *curr = [alternations objectAtIndex:i]; 977 | curr.parent = a; 978 | prev.nextSibling = curr; 979 | prev = curr; 980 | } 981 | 982 | g = [[WTReGroup alloc] init]; 983 | g.children = [NSArray arrayWithObject:a]; 984 | g.capturing = enclosed; 985 | g.sourceRange = a.sourceRange; 986 | 987 | a.parent = g; 988 | 989 | if (_finished && !enclosed) 990 | { 991 | a.nextSibling = lastnode; 992 | lastnode.parent = g; 993 | g.children = [NSArray arrayWithObjects:a, lastnode, nil]; 994 | } 995 | } 996 | 997 | return g; 998 | } 999 | 1000 | - (NSString*)reformatString:(NSString *)input 1001 | { 1002 | // empty strings are ok 1003 | if (input == nil || [input isEqualToString:@""]) return input; 1004 | 1005 | NSMutableString *tInput = [input mutableCopy]; 1006 | 1007 | @autoreleasepool { 1008 | WTState *initialState = [[WTState alloc] init]; 1009 | WTState *finalState = [self processNode:_node fromState:initialState length:input.length]; 1010 | 1011 | WTState *x = [self nextState:initialState finalState:finalState input:tInput position:0]; 1012 | 1013 | return x.isFinal ? tInput : nil; 1014 | } 1015 | } 1016 | 1017 | - (WTState*)processNode:(WTReNode*)node fromState:(WTState*)state length:(NSUInteger)length 1018 | { 1019 | if ([node isKindOfClass:[WTReEndOfString class]]) 1020 | { 1021 | WTState *finalState = [[WTState alloc] init]; 1022 | finalState.isFinal = YES; 1023 | 1024 | WTTransition *tran = [[WTTransition alloc] init]; 1025 | tran.node = (WTReCharacterBase*)node; 1026 | tran.nextState = finalState; 1027 | [state.transitions addObject:tran]; 1028 | 1029 | return finalState; 1030 | } 1031 | else if ([node isKindOfClass:[WTReCharacterBase class]]) 1032 | { 1033 | WTState *finalState = [[WTState alloc] init]; 1034 | 1035 | WTTransition *tran = [[WTTransition alloc] init]; 1036 | tran.node = (WTReCharacterBase*)node; 1037 | tran.nextState = finalState; 1038 | [state.transitions addObject:tran]; 1039 | 1040 | return finalState; 1041 | } 1042 | else if ([node isKindOfClass:[WTReQuantifier class]]) 1043 | { 1044 | WTReQuantifier *qtf = (WTReQuantifier*)node; 1045 | 1046 | WTState *curState = state; 1047 | for (NSUInteger i = 0; i < qtf.countFrom; i++) { 1048 | curState = [self processNode:qtf.child fromState:curState length:length]; 1049 | } 1050 | 1051 | if (qtf.countTo == qtf.countFrom) 1052 | { 1053 | // strict quantifier 1054 | return curState; 1055 | } 1056 | 1057 | WTState *finalState = [[WTState alloc] init]; 1058 | 1059 | for (NSUInteger i = qtf.countFrom; i < MIN(qtf.countTo, length); i++) { 1060 | WTState *nextState = [self processNode:qtf.child fromState:curState length:length]; 1061 | 1062 | WTTransition *tran = [[WTTransition alloc] init]; 1063 | tran.node = nil; 1064 | tran.nextState = finalState; 1065 | 1066 | if (qtf.greedy) 1067 | [curState.transitions addObject:tran]; 1068 | else 1069 | [curState.transitions insertObject:tran atIndex:0]; 1070 | 1071 | curState = nextState; 1072 | } 1073 | 1074 | WTTransition *tran = [[WTTransition alloc] init]; 1075 | tran.node = nil; 1076 | tran.nextState = finalState; 1077 | [curState.transitions addObject:tran]; 1078 | 1079 | return finalState; 1080 | } 1081 | else if ([node isKindOfClass:[WTReGroup class]]) 1082 | { 1083 | WTReGroup *grp = (WTReGroup*)node; 1084 | 1085 | WTState *curState = state; 1086 | for (NSUInteger i = 0; i < grp.children.count; i++) { 1087 | curState = [self processNode:[grp.children objectAtIndex:i] fromState:curState length:length]; 1088 | } 1089 | 1090 | if (!grp.capturing && grp.children.count == 1 && [[grp.children objectAtIndex:0] isKindOfClass:[WTReLiteral class]]) 1091 | { 1092 | WTTransition *tran = [[WTTransition alloc] init]; 1093 | tran.node = nil; 1094 | tran.bypassNode = (WTReLiteral*)[grp.children objectAtIndex:0]; 1095 | tran.nextState = curState; 1096 | [state.transitions addObject:tran]; 1097 | } 1098 | 1099 | return curState; 1100 | } 1101 | else if ([node isKindOfClass:[WTReAlternation class]]) 1102 | { 1103 | WTReAlternation *alt = (WTReAlternation*)node; 1104 | 1105 | WTState *finalState = [[WTState alloc] init]; 1106 | 1107 | for (NSUInteger i = 0; i < alt.children.count; i++) { 1108 | WTState *curState = [self processNode:[alt.children objectAtIndex:i] fromState:state length:length]; 1109 | 1110 | WTTransition *tran = [[WTTransition alloc] init]; 1111 | tran.node = nil; 1112 | tran.nextState = finalState; 1113 | [curState.transitions addObject:tran]; 1114 | } 1115 | 1116 | return finalState; 1117 | } 1118 | else 1119 | { 1120 | NSAssert(YES, @"Unsupported node type"); 1121 | return nil; 1122 | } 1123 | } 1124 | 1125 | - (WTState*)nextState:(WTState*)state finalState:(WTState*)final input:(NSMutableString*)input position:(NSUInteger)pos 1126 | { 1127 | if (state.isFinal) return state; 1128 | 1129 | if (pos > input.length) return final; 1130 | 1131 | for (WTTransition *tran in state.transitions) { 1132 | 1133 | NSUInteger nextPos = pos; 1134 | 1135 | if (tran.node != nil) { 1136 | unichar c = (pos < input.length) ? [input characterAtIndex:pos] : 0; 1137 | if (![tran.node matchesCharacter:c]) 1138 | { 1139 | if (c == 0) return final; 1140 | #ifdef DEBUG 1141 | //NSLog(@"Fail: %@ @ %u", [tran.node displayString:_pattern], pos); 1142 | #endif 1143 | continue; 1144 | } 1145 | else 1146 | { 1147 | #ifdef DEBUG 1148 | //NSLog(@"Pass: %@ @ %u", [tran.node displayString:_pattern], pos); 1149 | #endif 1150 | } 1151 | nextPos += 1; 1152 | } 1153 | 1154 | WTState *s = [self nextState:tran.nextState finalState:final input:input position:nextPos]; 1155 | if (s.isFinal) 1156 | { 1157 | if (tran.bypassNode != nil) 1158 | [input insertString:[NSString stringWithFormat:@"%c", tran.bypassNode.character] atIndex:nextPos]; 1159 | 1160 | return s; 1161 | } 1162 | } 1163 | 1164 | return nil; 1165 | } 1166 | 1167 | @end 1168 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/Library/WTReTextField/WTReTextField.h: -------------------------------------------------------------------------------- 1 | // 2 | // WTReTextField.h 3 | // WTReTextField 4 | // 5 | // Created by Alex Skalozub on 5/5/13. 6 | // Copyright (c) 2013 Alex Skalozub. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 9 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | // 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: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | // 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 17 | // IN THE SOFTWARE. 18 | // 19 | 20 | #import 21 | 22 | @class WTReParser; 23 | 24 | @interface WTReTextField : UITextField 25 | { 26 | NSString *_lastAcceptedValue; 27 | WTReParser *_parser; 28 | } 29 | 30 | @property (strong, nonatomic) NSString *pattern; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /DemoInPutPasswordView/Library/WTReTextField/WTReTextField.m: -------------------------------------------------------------------------------- 1 | // 2 | // WTReTextField.m 3 | // WTReTextField 4 | // 5 | // Created by Alex Skalozub on 5/5/13. 6 | // Copyright (c) 2013 Alex Skalozub. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 9 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | // 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: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | // 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 17 | // IN THE SOFTWARE. 18 | // 19 | 20 | #import "WTReTextField.h" 21 | #import "WTReParser.h" 22 | 23 | @implementation WTReTextField 24 | 25 | - (id)initWithFrame:(CGRect)frame 26 | { 27 | self = [super initWithFrame:frame]; 28 | if (self) 29 | { 30 | _lastAcceptedValue = nil; 31 | _parser = nil; 32 | [self addTarget:self action:@selector(formatInput:) forControlEvents:UIControlEventEditingChanged]; 33 | } 34 | return self; 35 | } 36 | 37 | - (id)initWithCoder:(NSCoder *)aDecoder 38 | { 39 | self = [super initWithCoder:aDecoder]; 40 | if (self) 41 | { 42 | _lastAcceptedValue = nil; 43 | _parser = nil; 44 | [self addTarget:self action:@selector(formatInput:) forControlEvents:UIControlEventEditingChanged]; 45 | } 46 | return self; 47 | } 48 | 49 | - (void)dealloc 50 | { 51 | _lastAcceptedValue = nil; 52 | _parser = nil; 53 | [self removeTarget:self action:@selector(formatInput:) forControlEvents:UIControlEventEditingChanged]; 54 | } 55 | 56 | - (void)setPattern:(NSString *)pattern 57 | { 58 | if (pattern == nil || [pattern isEqualToString:@""]) 59 | _parser = nil; 60 | else 61 | _parser = [[WTReParser alloc] initWithPattern:pattern]; 62 | } 63 | 64 | - (NSString*)pattern 65 | { 66 | return _parser.pattern; 67 | } 68 | 69 | - (void)formatInput:(UITextField *)textField 70 | { 71 | if (_parser == nil) return; 72 | 73 | __block WTReParser *localParser = _parser; 74 | 75 | dispatch_async(dispatch_get_main_queue(), ^{ 76 | NSString *formatted = [localParser reformatString:textField.text]; 77 | if (formatted == nil) 78 | formatted = _lastAcceptedValue; 79 | else 80 | _lastAcceptedValue = formatted; 81 | NSString *newText = formatted; 82 | if (![textField.text isEqualToString:newText]) { 83 | textField.text = formatted; 84 | [self sendActionsForControlEvents:UIControlEventValueChanged]; 85 | } 86 | }); 87 | } 88 | 89 | //lumin添加 90 | -(void)setText:(NSString *)text 91 | { 92 | [super setText:text]; 93 | [self formatInput:self]; 94 | } 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Mr Lu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DemoInPutPasswordView 2 | 仿微信支付密码输入框的效果 3 | 4 | 其中的文本框使用了第三方库[WTReTextField](https://github.com/pieceofsummer/WTReTextField ) (一个可通过正则表达式限制文本框输入内容的文本框。) 5 | 6 | ## 使用方法: 7 | - 1.将相关类导入到你的项目中 8 | - 2.添加引用#import "LMPopInputPasswordView.h",实现委托LMPopInputPassViewDelegate 9 | - 3.创建对象并设置委托,弹出视图: 10 | 11 | ``` 12 | LMPopInputPasswordView *popView = [[LMPopInputPasswordView alloc]init]; 13 | popView.frame = CGRectMake((self.view.frame.size.width - 250)*0.5, 50, 250, 150); 14 | popView.delegate = self; 15 | [popView pop]; 16 | ``` 17 | 18 | ## 效果图: 19 | ![](https://github.com/lqcjdx/DemoInPutPasswordView/blob/master/input.gif) 20 | 21 | 22 | -------------------------------------------------------------------------------- /input.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApesTalk/DemoInPutPasswordView/d6a05f15f02fd825eb54522a0701d151272ed095/input.gif --------------------------------------------------------------------------------