├── .DS_Store ├── image.png ├── image2.png ├── JHVerificationCodeView ├── .DS_Store ├── ViewController.h ├── NextViewController.h ├── AppDelegate.h ├── main.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── AppDelegate.m ├── NextViewController.m ├── JHVerificationCodeView │ ├── JHVerificationCodeView.h │ └── JHVerificationCodeView.m └── ViewController.m ├── JHVerificationCodeView.xcodeproj ├── xcuserdata │ ├── mac1.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ ├── apple.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ ├── xuejinghao.xcuserdatad │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ └── haocold.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── JHVerificationCodeView.xcscheme ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ ├── mac1.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ ├── apple.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ ├── haocold.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ └── xuejinghao.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── project.pbxproj ├── JHVerificationCodeView.podspec ├── JHVerificationCodeViewTests ├── Info.plist └── JHVerificationCodeViewTests.m ├── LICENSE ├── CHANGELOG.md └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjh093/JHVerificationCodeView/HEAD/.DS_Store -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjh093/JHVerificationCodeView/HEAD/image.png -------------------------------------------------------------------------------- /image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjh093/JHVerificationCodeView/HEAD/image2.png -------------------------------------------------------------------------------- /JHVerificationCodeView/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjh093/JHVerificationCodeView/HEAD/JHVerificationCodeView/.DS_Store -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/xcuserdata/mac1.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/xcuserdata/apple.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/project.xcworkspace/xcuserdata/mac1.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjh093/JHVerificationCodeView/HEAD/JHVerificationCodeView.xcodeproj/project.xcworkspace/xcuserdata/mac1.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjh093/JHVerificationCodeView/HEAD/JHVerificationCodeView.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/project.xcworkspace/xcuserdata/haocold.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjh093/JHVerificationCodeView/HEAD/JHVerificationCodeView.xcodeproj/project.xcworkspace/xcuserdata/haocold.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/project.xcworkspace/xcuserdata/xuejinghao.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjh093/JHVerificationCodeView/HEAD/JHVerificationCodeView.xcodeproj/project.xcworkspace/xcuserdata/xuejinghao.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /JHVerificationCodeView/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // JHVerificationCodeView 4 | // 5 | // Created by HaoCold on 2017/8/25. 6 | // Copyright © 2017年 HaoCold. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /JHVerificationCodeView/NextViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NextViewController.h 3 | // JHVerificationCodeView 4 | // 5 | // Created by HaoCold on 2020/9/8. 6 | // Copyright © 2020 HaoCold. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NextViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /JHVerificationCodeView/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // JHVerificationCodeView 4 | // 5 | // Created by HaoCold on 2017/8/25. 6 | // Copyright © 2017年 HaoCold. 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 | -------------------------------------------------------------------------------- /JHVerificationCodeView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // JHVerificationCodeView 4 | // 5 | // Created by HaoCold on 2017/8/25. 6 | // Copyright © 2017年 HaoCold. 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 | -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/xcuserdata/mac1.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | JHVerificationCodeView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/xcuserdata/xuejinghao.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | JHVerificationCodeView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | JHVerificationCodeView.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /JHVerificationCodeView.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | s.name = "JHVerificationCodeView" 4 | s.version = "1.3.7" 5 | s.summary = "A simple Verification Code View." 6 | s.homepage = "https://github.com/xjh093/JHVerificationCodeView" 7 | s.license = "MIT" 8 | s.author = { "Haocold" => "xjh093@126.com" } 9 | s.platform = :ios, "8.0" 10 | s.source = { :git => "https://github.com/xjh093/JHVerificationCodeView.git", :tag => s.version } 11 | s.source_files = "JHVerificationCodeView/JHVerificationCodeView/*.{h,m}" 12 | s.framework = "UIKit" 13 | s.requires_arc = true 14 | 15 | end 16 | -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/xcuserdata/haocold.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | JHVerificationCodeView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 088BF8A61F4FAF3C00B5863B 16 | 17 | primary 18 | 19 | 20 | 088BF8BF1F4FAF3C00B5863B 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /JHVerificationCodeViewTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 xjh093 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 | -------------------------------------------------------------------------------- /JHVerificationCodeViewTests/JHVerificationCodeViewTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // JHVerificationCodeViewTests.m 3 | // JHVerificationCodeViewTests 4 | // 5 | // Created by HaoCold on 2017/8/25. 6 | // Copyright © 2017年 HaoCold. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JHVerificationCodeViewTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation JHVerificationCodeViewTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Logs 2 | 3 | ### 2020-09-08 4 | 1.add `autoShowKeyboardDelay` 5 | - 延迟弹出键盘 6 | 7 | --- 8 | 9 | ### 2020-09-01 10 | 1.add One Time Code 11 | - 验证码快捷自动填充 12 | 13 | --- 14 | 15 | ### 2019-12-24: 16 | 1. add `inputBoxFinishColors`、`underLineFinishColors`、`finishFonts`、`finishTextColors`. 17 | 2. add method `showInputFinishColorWithIndex:` 18 | 19 | --- 20 | 21 | ### 2019-08-28: 22 | 1. add `keyboardType` and `useSystemPasswordKeyboard`. 23 | - 键盘类型,系统密码键盘. 24 | 25 | --- 26 | 27 | ### 2019-08-23: 28 | 1. add `inputBlock`. 29 | - 输入回调. 30 | 31 | --- 32 | 33 | ### 2019-07-19: 34 | 1.add method `- (void)clear;` 35 | - 一键清空. 36 | 37 | 2.add `customInputHolder`. 38 | - 自定义输入占位字符. 39 | 40 | --- 41 | 42 | ### 2018-11-1: 43 | 1.add `underLineHighlightedColor`. 44 | - 下划线高亮. 45 | 46 | ### 2018-10-17 47 | 1.add `FlickerAnimation`,`underline`. 48 | - 光标动画,下划线. 49 | 50 | --- 51 | 52 | ### 2018-10-15 53 | 1.add `inputBoxCornerRadius`,`inputBoxHighlightedColor`,and `autoShowKeyboard`. 54 | - 输入框圆角,输入框高亮,自动显示键盘. 55 | 56 | --- 57 | 58 | ### 2018-10-11 59 | 1.add `inputType`. 60 | - 输入类型限制. 61 | 62 | --- 63 | 64 | ### 2018-6-25 65 | 1.add `secureTextEntry`. 66 | - 密文模式. 67 | 68 | --- 69 | 70 | ### 2018-4-19: 71 | 1.`inputBoxSpacing` can be negative. 72 | - 输入框间隔可设置成负数,让输入框连在一起. 73 | 74 | --- 75 | 76 | ### 2017-8-25: 77 | 1.upload. 78 | - 上传. 79 | -------------------------------------------------------------------------------- /JHVerificationCodeView/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /JHVerificationCodeView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /JHVerificationCodeView/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JHVerificationCodeView 2 | A single authentication code input box 3 | - 单个的验证码输入框 4 | 5 | --- 6 | 7 | # Version 8 | Latest release version: 9 | - [1.3.7](https://github.com/xjh093/JHVerificationCodeView/releases) ❌ out of date! 10 | 11 | - [1.3.8] download master version for use. (2024-05-11 15:06:24) 12 | 13 | Swift version: 14 | - [JHVerifyCodeView](https://github.com/xjh093/JHVerifyCodeView) 15 | 16 | --- 17 | 18 | # Cocoapods 19 | 20 | `pod "JHVerificationCodeView"` 21 | 22 | --- 23 | 24 | # What 25 | 26 | ![image](https://github.com/xjh093/JHVerificationCodeView/blob/master/image.png) 27 | 28 | ![image](https://github.com/xjh093/JHVerificationCodeView/blob/master/image2.png) 29 | 30 | --- 31 | 32 | # Usage 33 | 34 | ``` 35 | JHVCConfig *config = [[JHVCConfig alloc] init]; 36 | config.inputBoxNumber = 6; 37 | config.inputBoxSpacing = 5; 38 | config.inputBoxWidth = 33; 39 | config.inputBoxHeight = 28; 40 | config.tintColor = [UIColor blackColor]; 41 | config.secureTextEntry = YES; 42 | config.inputBoxColor = [UIColor brownColor]; 43 | config.font = [UIFont boldSystemFontOfSize:16]; 44 | config.textColor = [UIColor brownColor]; 45 | config.inputType = JHVCConfigInputType_Number_Alphabet; // Default 46 | 47 | [self.view addSubview:({ 48 | JHVerificationCodeView *codeView = 49 | [[JHVerificationCodeView alloc] initWithFrame:CGRectMake(10, 100, kScreenWidth-20, 30) 50 | config:config]; 51 | codeView.finishBlock = ^(NSString *code) { 52 | label.text = code; 53 | }; 54 | codeView; 55 | })]; 56 | ``` 57 | 58 | --- 59 | 60 | # Logs 61 | 62 | - change log: [click here](https://github.com/xjh093/JHVerificationCodeView/blob/master/CHANGELOG.md) 63 | 64 | --- 65 | 66 | # More detail in Demo :) 67 | -------------------------------------------------------------------------------- /JHVerificationCodeView/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // JHVerificationCodeView 4 | // 5 | // Created by HaoCold on 2017/8/25. 6 | // Copyright © 2017年 HaoCold. 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 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /JHVerificationCodeView/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /JHVerificationCodeView/NextViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NextViewController.m 3 | // JHVerificationCodeView 4 | // 5 | // Created by HaoCold on 2020/9/8. 6 | // Copyright © 2020 HaoCold. All rights reserved. 7 | // 8 | 9 | #import "NextViewController.h" 10 | #import "JHVerificationCodeView.h" 11 | 12 | #define kScreenWidth [UIScreen mainScreen].bounds.size.width 13 | #define kScreenHeight [UIScreen mainScreen].bounds.size.height 14 | 15 | @interface NextViewController () 16 | 17 | @end 18 | 19 | @implementation NextViewController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | // Do any additional setup after loading the view. 24 | 25 | self.title = @"自动弹出键盘"; 26 | self.view.backgroundColor = [UIColor whiteColor]; 27 | 28 | [self jhSetupViews]; 29 | } 30 | 31 | - (void)jhSetupViews 32 | { 33 | // example 1 34 | { 35 | UILabel *label = [[UILabel alloc] init]; 36 | label.frame = CGRectMake(0, 120, kScreenWidth, 30); 37 | label.textAlignment = 1; 38 | label.text = @"InputType: Number & Alphabet"; 39 | [self.view addSubview:label]; 40 | 41 | JHVCConfig *config = [[JHVCConfig alloc] init]; 42 | config.inputBoxNumber = 6; 43 | config.inputBoxSpacing = 5; 44 | config.inputBoxWidth = 33; 45 | config.inputBoxHeight = 28; 46 | config.tintColor = [UIColor blackColor]; 47 | config.secureTextEntry = NO; 48 | config.inputBoxColor = [UIColor brownColor]; 49 | config.font = [UIFont boldSystemFontOfSize:16]; 50 | config.textColor = [UIColor blueColor]; 51 | config.inputType = JHVCConfigInputType_Number_Alphabet; 52 | 53 | 54 | config.inputBoxBorderWidth = 1; 55 | config.inputBoxCornerRadius = 5; 56 | 57 | // 自动弹出键盘 58 | config.autoShowKeyboard = YES; 59 | config.autoShowKeyboardDelay = 0.7; 60 | 61 | config.inputBoxFinishColors = @[[UIColor redColor],[UIColor orangeColor]]; 62 | config.finishFonts = @[[UIFont boldSystemFontOfSize:20],[UIFont systemFontOfSize:20]]; 63 | config.finishTextColors = @[[UIColor greenColor],[UIColor orangeColor]]; 64 | 65 | [self.view addSubview:({ 66 | 67 | UILabel *label = [[UILabel alloc] init]; 68 | label.frame = CGRectMake(0, 180, kScreenWidth, 30); 69 | label.textAlignment = 1; 70 | [self.view addSubview:label]; 71 | 72 | JHVerificationCodeView *codeView = 73 | [[JHVerificationCodeView alloc] initWithFrame:CGRectMake(10, 150, kScreenWidth-20, 30) 74 | config:config]; 75 | codeView.finishBlock = ^(JHVerificationCodeView *codeView, NSString *code) { 76 | label.text = code; 77 | 78 | // 根据最后输入结果,判断显示哪种颜色 79 | NSUInteger index = [code isEqualToString:@"123asd"] ? 1 : 0; 80 | [codeView showInputFinishColorWithIndex:index]; 81 | }; 82 | codeView.inputBlock = ^(NSString *code) { 83 | NSLog(@"example 1 code:%@",code); 84 | }; 85 | codeView.tag = 100; 86 | codeView; 87 | })]; 88 | } 89 | } 90 | 91 | 92 | /* 93 | #pragma mark - Navigation 94 | 95 | // In a storyboard-based application, you will often want to do a little preparation before navigation 96 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 97 | // Get the new view controller using [segue destinationViewController]. 98 | // Pass the selected object to the new view controller. 99 | } 100 | */ 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/xcuserdata/haocold.xcuserdatad/xcschemes/JHVerificationCodeView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /JHVerificationCodeView/JHVerificationCodeView/JHVerificationCodeView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JHVerificationCodeView.h 3 | // JHKit 4 | // 5 | // Created by HaoCold on 2017/8/21. 6 | // Copyright © 2017年 HaoCold. All rights reserved. 7 | // 8 | // MIT License 9 | // 10 | // Copyright (c) 2017 xjh093 11 | // 12 | // Permission is hereby granted, free of charge, to any person obtaining a copy 13 | // of this software and associated documentation files (the "Software"), to deal 14 | // in the Software without restriction, including without limitation the rights 15 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | // copies of the Software, and to permit persons to whom the Software is 17 | // furnished to do so, subject to the following conditions: 18 | // 19 | // The above copyright notice and this permission notice shall be included in all 20 | // copies or substantial portions of the Software. 21 | // 22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | // SOFTWARE. 29 | 30 | // version: 1.3.8 31 | // date: 2024-05-11 32 | 33 | #import 34 | 35 | typedef NS_ENUM(NSUInteger, JHVCConfigInputType) { 36 | JHVCConfigInputType_Number_Alphabet, 37 | JHVCConfigInputType_Number, 38 | JHVCConfigInputType_Alphabet, 39 | }; 40 | 41 | @interface JHVCConfig : NSObject 42 | 43 | //============================ Initialization ============================ 44 | 45 | ///输入框个数 46 | @property (assign, nonatomic) NSInteger inputBoxNumber; 47 | ///单个输入框的宽度 48 | @property (assign, nonatomic) CGFloat inputBoxWidth; 49 | ///单个输入框的高度 50 | @property (assign, nonatomic) CGFloat inputBoxHeight; 51 | ///单个输入框的边框宽度, Default is 1 pixel 52 | @property (assign, nonatomic) CGFloat inputBoxBorderWidth; 53 | ///单个输入框的边框圆角 54 | @property (assign, nonatomic) CGFloat inputBoxCornerRadius; 55 | ///输入框间距, Default is 5 56 | @property (assign, nonatomic) CGFloat inputBoxSpacing; 57 | ///左边距 58 | @property (assign, nonatomic) CGFloat leftMargin; 59 | ///单个输入框的颜色, Default is lightGrayColor 60 | @property (strong, nonatomic) UIColor *inputBoxColor; 61 | ///光标颜色, Default is blueColor 62 | @property (strong, nonatomic) UIColor *tintColor; 63 | ///显示 或 隐藏 64 | @property (assign, nonatomic) BOOL secureTextEntry; 65 | ///字体, Default is [UIFont boldSystemFontOfSize:16] 66 | @property (strong, nonatomic) UIFont *font; 67 | ///颜色, Default is [UIColor blackColor] 68 | @property (strong, nonatomic) UIColor *textColor; 69 | ///输入类型:数字+字母,数字,字母. Default is 'JHVCConfigInputType_Number_Alphabet' 70 | @property (nonatomic, assign) JHVCConfigInputType inputType; 71 | ///自动弹出键盘 72 | @property (nonatomic, assign) BOOL autoShowKeyboard; 73 | ///默认0.5 74 | @property (nonatomic, assign) CGFloat autoShowKeyboardDelay; 75 | ///光标闪烁动画, Default is YES 76 | @property (nonatomic, assign) BOOL showFlickerAnimation; 77 | ///显示下划线 78 | @property (nonatomic, assign) BOOL showUnderLine; 79 | ///下划线尺寸 80 | @property (nonatomic, assign) CGSize underLineSize; 81 | ///下划线颜色, Default is lightGrayColor 82 | @property (nonatomic, strong) UIColor *underLineColor; 83 | ///自定义的输入占位字符,secureTextEntry = NO,有效 84 | @property (nonatomic, copy) NSString *customInputHolder; 85 | ///设置键盘类型 86 | @property (nonatomic, assign) UIKeyboardType keyboardType; 87 | ///使用系统的密码键盘 88 | @property (nonatomic, assign) BOOL useSystemPasswordKeyboard; 89 | 90 | //============================ Input ============================ 91 | 92 | ///单个输入框输入时的颜色 93 | @property (strong, nonatomic) UIColor *inputBoxHighlightedColor; 94 | ///下划线高亮颜色 95 | @property (nonatomic, strong) UIColor *underLineHighlightedColor; 96 | 97 | //============================ Finish ============================ 98 | /* 输入完成后,可能根据不同的状态,显示不同的颜色。 */ 99 | 100 | ///单个输入框输入时的颜色 101 | @property (strong, nonatomic) NSArray *inputBoxFinishColors; 102 | ///下划线高亮颜色 103 | @property (nonatomic, strong) NSArray *underLineFinishColors; 104 | ///输入完成时字体 105 | @property (strong, nonatomic) NSArray *finishFonts; 106 | ///输入完成时颜色 107 | @property (strong, nonatomic) NSArray *finishTextColors; 108 | 109 | @end 110 | 111 | @interface JHVerificationCodeView : UIView 112 | 113 | @property (copy, nonatomic) void (^inputBlock)(NSString *code); 114 | @property (copy, nonatomic) void (^finishBlock)(JHVerificationCodeView *codeView, NSString *code); 115 | 116 | - (instancetype)initWithFrame:(CGRect)frame config:(JHVCConfig *)config; 117 | 118 | /** 119 | 清空所有输入 120 | */ 121 | - (void)clear; 122 | 123 | /** 124 | 输入完成后,调用此方法,根据 index 从 `Finish` 下的4个属性获取对应的值来设置颜色。 125 | 126 | @param index 用于从 `inputBoxFinishColors`、`underLineFinishColors`、`finishFonts`、`finishTextColors`中获取对应的值 127 | */ 128 | - (void)showInputFinishColorWithIndex:(NSUInteger)index; 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /JHVerificationCodeView/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // JHVerificationCodeView 4 | // 5 | // Created by HaoCold on 2017/8/25. 6 | // Copyright © 2017年 HaoCold. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "JHVerificationCodeView.h" 11 | #import "NextViewController.h" 12 | 13 | 14 | #define kScreenWidth [UIScreen mainScreen].bounds.size.width 15 | #define kScreenHeight [UIScreen mainScreen].bounds.size.height 16 | 17 | @interface ViewController () 18 | 19 | @end 20 | 21 | @implementation ViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | // Do any additional setup after loading the view, typically from a nib. 26 | 27 | self.title = @"验证码输入框"; 28 | 29 | [self jhSetupViews]; 30 | 31 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:({ 32 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 33 | button.titleLabel.font = [UIFont systemFontOfSize:16]; 34 | [button setTitle:@"清空" forState:0]; 35 | [button setTitleColor:[UIColor blackColor] forState:0]; 36 | [button sizeToFit]; 37 | [button addTarget:self action:@selector(clearAction) forControlEvents:1<<6]; 38 | button; 39 | })]; 40 | 41 | self.navigationItem.rightBarButtonItems = @[ 42 | [[UIBarButtonItem alloc] initWithCustomView:({ 43 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 44 | button.titleLabel.font = [UIFont systemFontOfSize:16]; 45 | [button setTitle:@"清空" forState:0]; 46 | [button setTitleColor:[UIColor blackColor] forState:0]; 47 | [button sizeToFit]; 48 | [button addTarget:self action:@selector(clearAction) forControlEvents:1<<6]; 49 | button; 50 | })], 51 | [[UIBarButtonItem alloc] initWithCustomView:({ 52 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 53 | button.titleLabel.font = [UIFont systemFontOfSize:16]; 54 | [button setTitle:@"跳转" forState:0]; 55 | [button setTitleColor:[UIColor blackColor] forState:0]; 56 | [button sizeToFit]; 57 | [button addTarget:self action:@selector(jumpAction) forControlEvents:1<<6]; 58 | button; 59 | })] 60 | ]; 61 | } 62 | 63 | - (void)jhSetupViews 64 | { 65 | // example 1 66 | { 67 | UILabel *label = [[UILabel alloc] init]; 68 | label.frame = CGRectMake(0, 120, kScreenWidth, 30); 69 | label.textAlignment = 1; 70 | label.text = @"InputType: Number & Alphabet"; 71 | [self.view addSubview:label]; 72 | 73 | JHVCConfig *config = [[JHVCConfig alloc] init]; 74 | config.inputBoxNumber = 6; 75 | config.inputBoxSpacing = 5; 76 | config.inputBoxWidth = 33; 77 | config.inputBoxHeight = 28; 78 | config.tintColor = [UIColor blackColor]; 79 | config.secureTextEntry = NO; 80 | config.inputBoxColor = [UIColor brownColor]; 81 | config.font = [UIFont boldSystemFontOfSize:16]; 82 | config.textColor = [UIColor blueColor]; 83 | config.inputType = JHVCConfigInputType_Number_Alphabet; 84 | 85 | config.inputBoxBorderWidth = 1; 86 | config.inputBoxCornerRadius = 5; 87 | 88 | //config.customInputHolder = @"🔒"; 89 | 90 | config.keyboardType = UIKeyboardTypeNumbersAndPunctuation; 91 | config.useSystemPasswordKeyboard = YES; 92 | 93 | config.inputBoxFinishColors = @[[UIColor redColor],[UIColor orangeColor]]; 94 | config.finishFonts = @[[UIFont boldSystemFontOfSize:20],[UIFont systemFontOfSize:20]]; 95 | config.finishTextColors = @[[UIColor greenColor],[UIColor orangeColor]]; 96 | 97 | [self.view addSubview:({ 98 | 99 | UILabel *label = [[UILabel alloc] init]; 100 | label.frame = CGRectMake(0, 180, kScreenWidth, 30); 101 | label.textAlignment = 1; 102 | [self.view addSubview:label]; 103 | 104 | JHVerificationCodeView *codeView = 105 | [[JHVerificationCodeView alloc] initWithFrame:CGRectMake(10, 150, kScreenWidth-20, 30) 106 | config:config]; 107 | codeView.finishBlock = ^(JHVerificationCodeView *codeView, NSString *code) { 108 | label.text = code; 109 | 110 | // 根据最后输入结果,判断显示哪种颜色 111 | NSUInteger index = [code isEqualToString:@"123asd"] ? 1 : 0; 112 | [codeView showInputFinishColorWithIndex:index]; 113 | }; 114 | codeView.inputBlock = ^(NSString *code) { 115 | NSLog(@"example 1 code:%@",code); 116 | }; 117 | codeView.tag = 100; 118 | codeView; 119 | })]; 120 | } 121 | 122 | // example 2 123 | { 124 | UILabel *label = [[UILabel alloc] init]; 125 | label.frame = CGRectMake(0, 210, kScreenWidth, 30); 126 | label.textAlignment = 1; 127 | label.text = @"InputType: Number"; 128 | [self.view addSubview:label]; 129 | 130 | JHVCConfig *config = [[JHVCConfig alloc] init]; 131 | config.inputBoxNumber = 6; 132 | config.inputBoxSpacing = 5; 133 | config.inputBoxWidth = 33; 134 | config.inputBoxHeight = 28; 135 | config.tintColor = [UIColor greenColor]; 136 | config.secureTextEntry = NO; 137 | config.inputBoxColor = [UIColor brownColor]; 138 | config.font = [UIFont boldSystemFontOfSize:16]; 139 | config.textColor = [UIColor cyanColor]; 140 | config.inputType = JHVCConfigInputType_Number; 141 | 142 | config.inputBoxBorderWidth = 1; 143 | config.inputBoxHighlightedColor = [UIColor purpleColor]; 144 | 145 | config.customInputHolder = @"🈲"; 146 | 147 | config.inputBoxFinishColors = @[[UIColor orangeColor],[UIColor redColor]]; 148 | config.finishFonts = @[[UIFont boldSystemFontOfSize:20],[UIFont systemFontOfSize:20]]; 149 | config.finishTextColors = @[[UIColor orangeColor],[UIColor greenColor]]; 150 | 151 | [self.view addSubview:({ 152 | 153 | UILabel *label = [[UILabel alloc] init]; 154 | label.frame = CGRectMake(0, 270, kScreenWidth, 30); 155 | label.textAlignment = 1; 156 | [self.view addSubview:label]; 157 | 158 | JHVerificationCodeView *codeView = 159 | [[JHVerificationCodeView alloc] initWithFrame:CGRectMake(10, 240, kScreenWidth-20, 30) 160 | config:config]; 161 | codeView.finishBlock = ^(JHVerificationCodeView *codeView, NSString *code) { 162 | label.text = code; 163 | 164 | // 根据最后输入结果,判断显示哪种颜色 165 | NSUInteger index = [code isEqualToString:@"123456"] ? 1 : 0; 166 | [codeView showInputFinishColorWithIndex:index]; 167 | }; 168 | codeView.inputBlock = ^(NSString *code) { 169 | NSLog(@"example 2 code:%@",code); 170 | }; 171 | codeView.tag = 200; 172 | codeView; 173 | })]; 174 | } 175 | 176 | // example 3 177 | { 178 | UILabel *label = [[UILabel alloc] init]; 179 | label.frame = CGRectMake(0, 300, kScreenWidth, 30); 180 | label.textAlignment = 1; 181 | label.text = @"InputType: Alphabet"; 182 | [self.view addSubview:label]; 183 | 184 | JHVCConfig *config = [[JHVCConfig alloc] init]; 185 | config.inputBoxNumber = 6; 186 | config.inputBoxSpacing = -1; 187 | config.inputBoxWidth = 33; 188 | config.inputBoxHeight = 28; 189 | config.tintColor = [UIColor redColor]; 190 | config.secureTextEntry = NO; 191 | config.inputBoxColor = [UIColor brownColor]; 192 | config.font = [UIFont boldSystemFontOfSize:16]; 193 | config.textColor = [UIColor grayColor]; 194 | config.inputType = JHVCConfigInputType_Alphabet; 195 | 196 | config.inputBoxBorderWidth = 1; 197 | 198 | config.customInputHolder = @"❄️"; 199 | 200 | [self.view addSubview:({ 201 | 202 | UILabel *label = [[UILabel alloc] init]; 203 | label.frame = CGRectMake(0, 360, kScreenWidth, 30); 204 | label.textAlignment = 1; 205 | [self.view addSubview:label]; 206 | 207 | JHVerificationCodeView *codeView = 208 | [[JHVerificationCodeView alloc] initWithFrame:CGRectMake(10, 330, kScreenWidth-20, 30) 209 | config:config]; 210 | codeView.finishBlock = ^(JHVerificationCodeView *codeView, NSString *code) { 211 | label.text = code; 212 | }; 213 | codeView.inputBlock = ^(NSString *code) { 214 | NSLog(@"example 3 code:%@",code); 215 | }; 216 | codeView.tag = 300; 217 | codeView; 218 | })]; 219 | } 220 | 221 | // example 4 222 | { 223 | UILabel *label = [[UILabel alloc] init]; 224 | label.frame = CGRectMake(0, 390, kScreenWidth, 30); 225 | label.textAlignment = 1; 226 | label.text = @"InputType: Alphabet"; 227 | [self.view addSubview:label]; 228 | 229 | JHVCConfig *config = [[JHVCConfig alloc] init]; 230 | config.inputBoxNumber = 4; 231 | config.inputBoxSpacing = 4; 232 | config.inputBoxWidth = 33; 233 | config.inputBoxHeight = 28; 234 | config.tintColor = [UIColor blueColor]; 235 | config.secureTextEntry = YES; 236 | config.inputBoxColor = [UIColor clearColor]; 237 | config.font = [UIFont boldSystemFontOfSize:20]; 238 | config.textColor = [UIColor grayColor]; 239 | config.inputType = JHVCConfigInputType_Alphabet; 240 | 241 | config.inputBoxBorderWidth = 1; 242 | config.showUnderLine = YES; 243 | config.underLineSize = CGSizeMake(33, 2); 244 | config.underLineColor = [UIColor brownColor]; 245 | config.underLineHighlightedColor = [UIColor redColor]; 246 | 247 | config.underLineFinishColors = @[[UIColor blueColor],[UIColor orangeColor]]; 248 | config.finishFonts = @[[UIFont boldSystemFontOfSize:20],[UIFont systemFontOfSize:20]]; 249 | config.finishTextColors = @[[UIColor greenColor],[UIColor orangeColor]]; 250 | 251 | [self.view addSubview:({ 252 | 253 | UILabel *label = [[UILabel alloc] init]; 254 | label.frame = CGRectMake(0, 450, kScreenWidth, 30); 255 | label.textAlignment = 1; 256 | [self.view addSubview:label]; 257 | 258 | JHVerificationCodeView *codeView = 259 | [[JHVerificationCodeView alloc] initWithFrame:CGRectMake(10, 420, kScreenWidth-20, 30) 260 | config:config]; 261 | codeView.finishBlock = ^(JHVerificationCodeView *codeView, NSString *code) { 262 | label.text = code; 263 | 264 | // 根据最后输入结果,判断显示哪种颜色 265 | NSUInteger index = [code isEqualToString:@"Asdf"] ? 1 : 0; 266 | [codeView showInputFinishColorWithIndex:index]; 267 | }; 268 | codeView.inputBlock = ^(NSString *code) { 269 | NSLog(@"example 4 code:%@",code); 270 | }; 271 | codeView.tag = 400; 272 | codeView; 273 | })]; 274 | } 275 | } 276 | 277 | 278 | - (void)clearAction 279 | { 280 | JHVerificationCodeView *codeView1 = [self.view viewWithTag:100]; 281 | JHVerificationCodeView *codeView2 = [self.view viewWithTag:200]; 282 | JHVerificationCodeView *codeView3 = [self.view viewWithTag:300]; 283 | JHVerificationCodeView *codeView4 = [self.view viewWithTag:400]; 284 | 285 | [codeView1 clear]; 286 | [codeView2 clear]; 287 | [codeView3 clear]; 288 | [codeView4 clear]; 289 | 290 | } 291 | 292 | - (void)jumpAction 293 | { 294 | [self.navigationController pushViewController:[[NextViewController alloc] init] animated:YES]; 295 | } 296 | 297 | - (void)didReceiveMemoryWarning { 298 | [super didReceiveMemoryWarning]; 299 | // Dispose of any resources that can be recreated. 300 | } 301 | 302 | 303 | @end 304 | -------------------------------------------------------------------------------- /JHVerificationCodeView/JHVerificationCodeView/JHVerificationCodeView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JHVerificationCodeView.m 3 | // JHKit 4 | // 5 | // Created by HaoCold on 2017/8/21. 6 | // Copyright © 2017年 HaoCold. All rights reserved. 7 | // 8 | // MIT License 9 | // 10 | // Copyright (c) 2017 xjh093 11 | // 12 | // Permission is hereby granted, free of charge, to any person obtaining a copy 13 | // of this software and associated documentation files (the "Software"), to deal 14 | // in the Software without restriction, including without limitation the rights 15 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | // copies of the Software, and to permit persons to whom the Software is 17 | // furnished to do so, subject to the following conditions: 18 | // 19 | // The above copyright notice and this permission notice shall be included in all 20 | // copies or substantial portions of the Software. 21 | // 22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | // SOFTWARE. 29 | 30 | #import "JHVerificationCodeView.h" 31 | 32 | #define kFlickerAnimation @"kFlickerAnimation" 33 | 34 | @implementation JHVCConfig 35 | 36 | - (instancetype)init{ 37 | if (self = [super init]) { 38 | _inputBoxBorderWidth = 1.0/[UIScreen mainScreen].scale; 39 | _inputBoxSpacing = 5; 40 | _inputBoxColor = [UIColor lightGrayColor]; 41 | _tintColor = [UIColor blueColor]; 42 | _font = [UIFont boldSystemFontOfSize:16]; 43 | _textColor = [UIColor blackColor]; 44 | _showFlickerAnimation = YES; 45 | _underLineColor = [UIColor lightGrayColor]; 46 | _autoShowKeyboardDelay = 0.5; 47 | } 48 | return self; 49 | } 50 | 51 | @end 52 | 53 | @interface JHVerificationCodeView() 54 | @property (strong, nonatomic) JHVCConfig *config; 55 | @property (strong, nonatomic) UITextField *textView; 56 | @property (nonatomic, assign) BOOL inputFinish; 57 | @property (nonatomic, assign) NSUInteger inputFinishIndex; 58 | /// 存放光标 layer --- 2024-05-11 14:44:14 59 | @property (nonatomic, strong) NSMutableArray *layerArray; 60 | @end 61 | 62 | @implementation JHVerificationCodeView 63 | 64 | - (void)dealloc{ 65 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 66 | } 67 | 68 | - (instancetype)initWithFrame:(CGRect)frame config:(JHVCConfig *)config{ 69 | if (self = [super initWithFrame:frame]) { 70 | _config = config; 71 | [self jhSetupViews:frame]; 72 | } 73 | return self; 74 | } 75 | 76 | - (void)jhSetupViews:(CGRect)frame 77 | { 78 | if (frame.size.width <= 0 || 79 | frame.size.height <= 0 || 80 | _config.inputBoxNumber == 0 || 81 | _config.inputBoxWidth > frame.size.width) { 82 | return; 83 | } 84 | 85 | _layerArray = @[].mutableCopy; 86 | 87 | //优先考虑 inputBoxWidth 88 | CGFloat inputBoxSpacing = _config.inputBoxSpacing; 89 | 90 | CGFloat inputBoxWidth = 0; 91 | if (_config.inputBoxWidth > 0) { 92 | inputBoxWidth = _config.inputBoxWidth; 93 | } 94 | 95 | CGFloat leftMargin = 0; 96 | if (inputBoxWidth > 0) { 97 | _config.leftMargin = (CGRectGetWidth(frame)-inputBoxWidth*_config.inputBoxNumber-inputBoxSpacing*(_config.inputBoxNumber-1))*0.5; 98 | leftMargin = _config.leftMargin; 99 | }else{ 100 | _config.inputBoxWidth = (CGRectGetWidth(frame)-inputBoxSpacing*(_config.inputBoxNumber-1)-_config.leftMargin*2)/_config.inputBoxNumber; 101 | inputBoxWidth = _config.inputBoxWidth; 102 | } 103 | 104 | if (_config.leftMargin < 0) { 105 | _config.leftMargin = 0; 106 | _config.inputBoxWidth = (CGRectGetWidth(frame)-inputBoxSpacing*(_config.inputBoxNumber-1)-_config.leftMargin*2)/_config.inputBoxNumber; 107 | 108 | leftMargin = _config.leftMargin; 109 | inputBoxWidth = _config.inputBoxWidth; 110 | } 111 | 112 | CGFloat inputBoxHeight = 0; 113 | if (_config.inputBoxHeight > CGRectGetHeight(frame)) { 114 | _config.inputBoxHeight = CGRectGetHeight(frame); 115 | } 116 | inputBoxHeight = _config.inputBoxHeight; 117 | 118 | if (_config.showUnderLine) { 119 | if (_config.underLineSize.width <= 0) { 120 | CGSize size = _config.underLineSize; 121 | size.width = inputBoxWidth; 122 | _config.underLineSize = size; 123 | } 124 | if (_config.underLineSize.height <= 0) { 125 | CGSize size = _config.underLineSize; 126 | size.height = 1; 127 | _config.underLineSize = size; 128 | } 129 | } 130 | 131 | for (int i = 0; i < _config.inputBoxNumber; ++i) { 132 | UITextField *textField = [[UITextField alloc] init]; 133 | textField.frame = CGRectMake(_config.leftMargin+(inputBoxWidth+inputBoxSpacing)*i, (CGRectGetHeight(frame)-inputBoxHeight)*0.5, inputBoxWidth, inputBoxHeight); 134 | textField.textAlignment = 1; 135 | if (_config.inputBoxBorderWidth) { 136 | textField.layer.borderWidth = _config.inputBoxBorderWidth; 137 | } 138 | if (_config.inputBoxCornerRadius) { 139 | textField.layer.cornerRadius = _config.inputBoxCornerRadius; 140 | } 141 | if (_config.inputBoxColor) { 142 | textField.layer.borderColor = _config.inputBoxColor.CGColor; 143 | } 144 | if (_config.tintColor) { 145 | if (inputBoxWidth > 2 && inputBoxHeight > 8) { 146 | CGFloat w = 2, y = 4, x = (inputBoxWidth-w)/2, h = inputBoxHeight-2*y; 147 | [textField.layer addSublayer:({ 148 | UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(x,y,w,h)]; 149 | CAShapeLayer *layer = [CAShapeLayer layer]; 150 | layer.path = path.CGPath; 151 | layer.fillColor = _config.tintColor.CGColor; 152 | [layer addAnimation:[self xx_alphaAnimation] forKey:kFlickerAnimation]; 153 | if (i != 0) { 154 | layer.hidden = YES; 155 | } 156 | 157 | [_layerArray addObject:layer]; 158 | layer; 159 | })]; 160 | } 161 | } 162 | if (_config.secureTextEntry) { 163 | textField.secureTextEntry = _config.secureTextEntry; 164 | } 165 | if (_config.font){ 166 | textField.font = _config.font; 167 | } 168 | if (_config.textColor) { 169 | textField.textColor = _config.textColor; 170 | } 171 | if (_config.showUnderLine) { 172 | CGFloat x = (inputBoxWidth-_config.underLineSize.width)/2.0; 173 | CGFloat y = (inputBoxHeight-_config.underLineSize.height); 174 | CGRect frame = CGRectMake(x, y, _config.underLineSize.width, _config.underLineSize.height); 175 | 176 | UIView *underLine = [[UIView alloc] init]; 177 | underLine.tag = 100; 178 | underLine.frame = frame; 179 | underLine.backgroundColor = _config.underLineColor; 180 | [textField addSubview:underLine]; 181 | 182 | } 183 | 184 | textField.tag = i; 185 | textField.userInteractionEnabled = NO; 186 | [self addSubview:textField]; 187 | } 188 | 189 | [self addGestureRecognizer:({ 190 | [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(xx_tap)]; 191 | })]; 192 | 193 | _textView = [[UITextField alloc] init]; 194 | _textView.frame = CGRectMake(0, CGRectGetHeight(frame), 0, 0); 195 | _textView.secureTextEntry = _config.useSystemPasswordKeyboard; 196 | _textView.keyboardType = _config.keyboardType; 197 | _textView.hidden = YES; 198 | if (@available(iOS 12.0, *)) { 199 | _textView.textContentType = UITextContentTypeOneTimeCode; 200 | } 201 | [self addSubview:_textView]; 202 | 203 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(xx_textChange:) name:UITextFieldTextDidChangeNotification object:_textView]; 204 | //[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(xx_didBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; 205 | 206 | if (_config.autoShowKeyboard) { 207 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_config.autoShowKeyboardDelay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 208 | [_textView becomeFirstResponder]; 209 | }); 210 | } 211 | } 212 | 213 | - (CABasicAnimation *)xx_alphaAnimation{ 214 | CABasicAnimation *alpha = [CABasicAnimation animationWithKeyPath:@"opacity"]; 215 | alpha.fromValue = @(1.0); 216 | alpha.toValue = @(0.0); 217 | alpha.duration = 1.0; 218 | alpha.repeatCount = CGFLOAT_MAX; 219 | alpha.removedOnCompletion = NO; 220 | alpha.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 221 | return alpha; 222 | } 223 | 224 | - (void)xx_tap{ 225 | [_textView becomeFirstResponder]; 226 | } 227 | 228 | - (void)xx_didBecomeActive{ 229 | // restart Flicker Animation 230 | if (_config.showFlickerAnimation && _textView.text.length < _layerArray.count) { 231 | CALayer *layer = _layerArray[_textView.text.length]; 232 | [layer removeAnimationForKey:kFlickerAnimation]; 233 | [layer addAnimation:[self xx_alphaAnimation] forKey:kFlickerAnimation]; 234 | } 235 | } 236 | 237 | - (void)xx_textChange:(NSNotification *)noti 238 | { 239 | //NSLog(@"%@",noti.object); 240 | if (_textView != noti.object) { 241 | return; 242 | } 243 | 244 | // set default 245 | [self xx_setDefault]; 246 | 247 | // trim space 248 | NSString *text = [_textView.text stringByReplacingOccurrencesOfString:@" " withString:@""]; 249 | 250 | // number & alphabet 251 | NSMutableString *mstr = @"".mutableCopy; 252 | for (int i = 0; i < text.length; ++i) { 253 | unichar c = [text characterAtIndex:i]; 254 | if (_config.inputType == JHVCConfigInputType_Number_Alphabet) { 255 | if ((c >= '0' && c <= '9') || 256 | (c >= 'A' && c <= 'Z') || 257 | (c >= 'a' && c <= 'z')) { 258 | [mstr appendFormat:@"%c",c]; 259 | } 260 | }else if (_config.inputType == JHVCConfigInputType_Number) { 261 | if ((c >= '0' && c <= '9')) { 262 | [mstr appendFormat:@"%c",c]; 263 | } 264 | }else if (_config.inputType == JHVCConfigInputType_Alphabet) { 265 | if ((c >= 'A' && c <= 'Z') || 266 | (c >= 'a' && c <= 'z')) { 267 | [mstr appendFormat:@"%c",c]; 268 | } 269 | } 270 | } 271 | 272 | text = mstr; 273 | NSInteger count = _config.inputBoxNumber; 274 | if (text.length > count) { 275 | text = [text substringToIndex:count]; 276 | } 277 | _textView.text = text; 278 | if (_inputBlock) { 279 | _inputBlock(text); 280 | } 281 | 282 | // set value 283 | [self xx_setValue:text]; 284 | 285 | // Flicker Animation 286 | [self xx_flickerAnimation:text]; 287 | 288 | if (_inputFinish) { 289 | [self xx_finish]; 290 | } 291 | } 292 | 293 | - (void)xx_setDefault 294 | { 295 | for (int i = 0; i < _config.inputBoxNumber; ++i) { 296 | UITextField *textField = self.subviews[i]; 297 | textField.text = @""; 298 | 299 | if (_config.inputBoxColor) { 300 | textField.layer.borderColor = _config.inputBoxColor.CGColor; 301 | } 302 | if (_config.showFlickerAnimation && _layerArray.count > i) { 303 | CALayer *layer = _layerArray[i]; 304 | layer.hidden = YES; 305 | [layer removeAnimationForKey:kFlickerAnimation]; 306 | } 307 | if (_config.showUnderLine) { 308 | UIView *underLine = [textField viewWithTag:100]; 309 | underLine.backgroundColor = _config.underLineColor; 310 | } 311 | } 312 | } 313 | 314 | - (void)xx_flickerAnimation:(NSString *)text 315 | { 316 | if (_config.showFlickerAnimation && text.length < _layerArray.count) { 317 | CALayer *layer = _layerArray[text.length]; 318 | layer.hidden = NO; 319 | [layer addAnimation:[self xx_alphaAnimation] forKey:kFlickerAnimation]; 320 | } 321 | } 322 | 323 | - (void)xx_setValue:(NSString *)text 324 | { 325 | _inputFinish = (text.length == _config.inputBoxNumber); 326 | 327 | for (int i = 0; i < text.length; ++i) { 328 | unichar c = [text characterAtIndex:i]; 329 | UITextField *textField = self.subviews[i]; 330 | textField.text = [NSString stringWithFormat:@"%c",c]; 331 | if (!textField.secureTextEntry && _config.customInputHolder.length > 0) { 332 | textField.text = _config.customInputHolder; 333 | } 334 | 335 | // Input Status 336 | UIFont *font = _config.font; 337 | UIColor *color = _config.textColor; 338 | UIColor *inputBoxColor = _config.inputBoxHighlightedColor; 339 | UIColor *underLineColor = _config.underLineHighlightedColor; 340 | 341 | // Finish Status 342 | if (_inputFinish) { 343 | if (_inputFinishIndex < _config.finishFonts.count) { 344 | font = _config.finishFonts[_inputFinishIndex]; 345 | } 346 | if (_inputFinishIndex < _config.finishTextColors.count) { 347 | color = _config.finishTextColors[_inputFinishIndex]; 348 | } 349 | if (_inputFinishIndex < _config.inputBoxFinishColors.count) { 350 | inputBoxColor = _config.inputBoxFinishColors[_inputFinishIndex]; 351 | } 352 | if (_inputFinishIndex < _config.underLineFinishColors.count) { 353 | underLineColor = _config.underLineFinishColors[_inputFinishIndex]; 354 | } 355 | } 356 | 357 | textField.font = font; 358 | textField.textColor = color; 359 | 360 | if (inputBoxColor) { 361 | textField.layer.borderColor = inputBoxColor.CGColor; 362 | } 363 | if (_config.showUnderLine && underLineColor) { 364 | UIView *underLine = [textField viewWithTag:100]; 365 | underLine.backgroundColor = underLineColor; 366 | } 367 | } 368 | } 369 | 370 | - (void)xx_finish 371 | { 372 | if (_finishBlock) { 373 | _finishBlock(self, _textView.text); 374 | } 375 | 376 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 377 | [self endEditing:YES]; 378 | }); 379 | } 380 | 381 | #pragma mark - public 382 | 383 | - (void)clear 384 | { 385 | _textView.text = @""; 386 | 387 | [self xx_setDefault]; 388 | [self xx_flickerAnimation:_textView.text]; 389 | } 390 | 391 | - (void)showInputFinishColorWithIndex:(NSUInteger)index 392 | { 393 | _inputFinishIndex = index; 394 | 395 | [self xx_setValue:_textView.text]; 396 | } 397 | 398 | @end 399 | -------------------------------------------------------------------------------- /JHVerificationCodeView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 088BF8AC1F4FAF3C00B5863B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 088BF8AB1F4FAF3C00B5863B /* main.m */; }; 11 | 088BF8AF1F4FAF3C00B5863B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 088BF8AE1F4FAF3C00B5863B /* AppDelegate.m */; }; 12 | 088BF8B21F4FAF3C00B5863B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 088BF8B11F4FAF3C00B5863B /* ViewController.m */; }; 13 | 088BF8B51F4FAF3C00B5863B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 088BF8B31F4FAF3C00B5863B /* Main.storyboard */; }; 14 | 088BF8B71F4FAF3C00B5863B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 088BF8B61F4FAF3C00B5863B /* Assets.xcassets */; }; 15 | 088BF8BA1F4FAF3C00B5863B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 088BF8B81F4FAF3C00B5863B /* LaunchScreen.storyboard */; }; 16 | 088BF8C51F4FAF3C00B5863B /* JHVerificationCodeViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 088BF8C41F4FAF3C00B5863B /* JHVerificationCodeViewTests.m */; }; 17 | 088BF8D21F4FAF7500B5863B /* JHVerificationCodeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 088BF8D11F4FAF7500B5863B /* JHVerificationCodeView.m */; }; 18 | 18EE78502507AA8000E7F10D /* NextViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 18EE784F2507AA8000E7F10D /* NextViewController.m */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | 088BF8C11F4FAF3C00B5863B /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = 088BF89F1F4FAF3C00B5863B /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = 088BF8A61F4FAF3C00B5863B; 27 | remoteInfo = JHVerificationCodeView; 28 | }; 29 | /* End PBXContainerItemProxy section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 088BF8A71F4FAF3C00B5863B /* JHVerificationCodeView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JHVerificationCodeView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 088BF8AB1F4FAF3C00B5863B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 34 | 088BF8AD1F4FAF3C00B5863B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 35 | 088BF8AE1F4FAF3C00B5863B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 36 | 088BF8B01F4FAF3C00B5863B /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 37 | 088BF8B11F4FAF3C00B5863B /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 38 | 088BF8B41F4FAF3C00B5863B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 39 | 088BF8B61F4FAF3C00B5863B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 40 | 088BF8B91F4FAF3C00B5863B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 41 | 088BF8BB1F4FAF3C00B5863B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 42 | 088BF8C01F4FAF3C00B5863B /* JHVerificationCodeViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JHVerificationCodeViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 088BF8C41F4FAF3C00B5863B /* JHVerificationCodeViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JHVerificationCodeViewTests.m; sourceTree = ""; }; 44 | 088BF8C61F4FAF3C00B5863B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | 088BF8D01F4FAF7500B5863B /* JHVerificationCodeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JHVerificationCodeView.h; sourceTree = ""; }; 46 | 088BF8D11F4FAF7500B5863B /* JHVerificationCodeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JHVerificationCodeView.m; sourceTree = ""; }; 47 | 18EE784E2507AA8000E7F10D /* NextViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NextViewController.h; sourceTree = ""; }; 48 | 18EE784F2507AA8000E7F10D /* NextViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NextViewController.m; sourceTree = ""; }; 49 | /* End PBXFileReference section */ 50 | 51 | /* Begin PBXFrameworksBuildPhase section */ 52 | 088BF8A41F4FAF3C00B5863B /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | 088BF8BD1F4FAF3C00B5863B /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXFrameworksBuildPhase section */ 67 | 68 | /* Begin PBXGroup section */ 69 | 088BF89E1F4FAF3C00B5863B = { 70 | isa = PBXGroup; 71 | children = ( 72 | 088BF8A91F4FAF3C00B5863B /* JHVerificationCodeView */, 73 | 088BF8C31F4FAF3C00B5863B /* JHVerificationCodeViewTests */, 74 | 088BF8A81F4FAF3C00B5863B /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 088BF8A81F4FAF3C00B5863B /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 088BF8A71F4FAF3C00B5863B /* JHVerificationCodeView.app */, 82 | 088BF8C01F4FAF3C00B5863B /* JHVerificationCodeViewTests.xctest */, 83 | ); 84 | name = Products; 85 | sourceTree = ""; 86 | }; 87 | 088BF8A91F4FAF3C00B5863B /* JHVerificationCodeView */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 088BF8CF1F4FAF7500B5863B /* JHVerificationCodeView */, 91 | 088BF8AD1F4FAF3C00B5863B /* AppDelegate.h */, 92 | 088BF8AE1F4FAF3C00B5863B /* AppDelegate.m */, 93 | 088BF8B01F4FAF3C00B5863B /* ViewController.h */, 94 | 088BF8B11F4FAF3C00B5863B /* ViewController.m */, 95 | 18EE784E2507AA8000E7F10D /* NextViewController.h */, 96 | 18EE784F2507AA8000E7F10D /* NextViewController.m */, 97 | 088BF8B31F4FAF3C00B5863B /* Main.storyboard */, 98 | 088BF8B61F4FAF3C00B5863B /* Assets.xcassets */, 99 | 088BF8B81F4FAF3C00B5863B /* LaunchScreen.storyboard */, 100 | 088BF8BB1F4FAF3C00B5863B /* Info.plist */, 101 | 088BF8AA1F4FAF3C00B5863B /* Supporting Files */, 102 | ); 103 | path = JHVerificationCodeView; 104 | sourceTree = ""; 105 | }; 106 | 088BF8AA1F4FAF3C00B5863B /* Supporting Files */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 088BF8AB1F4FAF3C00B5863B /* main.m */, 110 | ); 111 | name = "Supporting Files"; 112 | sourceTree = ""; 113 | }; 114 | 088BF8C31F4FAF3C00B5863B /* JHVerificationCodeViewTests */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 088BF8C41F4FAF3C00B5863B /* JHVerificationCodeViewTests.m */, 118 | 088BF8C61F4FAF3C00B5863B /* Info.plist */, 119 | ); 120 | path = JHVerificationCodeViewTests; 121 | sourceTree = ""; 122 | }; 123 | 088BF8CF1F4FAF7500B5863B /* JHVerificationCodeView */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 088BF8D01F4FAF7500B5863B /* JHVerificationCodeView.h */, 127 | 088BF8D11F4FAF7500B5863B /* JHVerificationCodeView.m */, 128 | ); 129 | path = JHVerificationCodeView; 130 | sourceTree = ""; 131 | }; 132 | /* End PBXGroup section */ 133 | 134 | /* Begin PBXNativeTarget section */ 135 | 088BF8A61F4FAF3C00B5863B /* JHVerificationCodeView */ = { 136 | isa = PBXNativeTarget; 137 | buildConfigurationList = 088BF8C91F4FAF3C00B5863B /* Build configuration list for PBXNativeTarget "JHVerificationCodeView" */; 138 | buildPhases = ( 139 | 088BF8A31F4FAF3C00B5863B /* Sources */, 140 | 088BF8A41F4FAF3C00B5863B /* Frameworks */, 141 | 088BF8A51F4FAF3C00B5863B /* Resources */, 142 | ); 143 | buildRules = ( 144 | ); 145 | dependencies = ( 146 | ); 147 | name = JHVerificationCodeView; 148 | productName = JHVerificationCodeView; 149 | productReference = 088BF8A71F4FAF3C00B5863B /* JHVerificationCodeView.app */; 150 | productType = "com.apple.product-type.application"; 151 | }; 152 | 088BF8BF1F4FAF3C00B5863B /* JHVerificationCodeViewTests */ = { 153 | isa = PBXNativeTarget; 154 | buildConfigurationList = 088BF8CC1F4FAF3C00B5863B /* Build configuration list for PBXNativeTarget "JHVerificationCodeViewTests" */; 155 | buildPhases = ( 156 | 088BF8BC1F4FAF3C00B5863B /* Sources */, 157 | 088BF8BD1F4FAF3C00B5863B /* Frameworks */, 158 | 088BF8BE1F4FAF3C00B5863B /* Resources */, 159 | ); 160 | buildRules = ( 161 | ); 162 | dependencies = ( 163 | 088BF8C21F4FAF3C00B5863B /* PBXTargetDependency */, 164 | ); 165 | name = JHVerificationCodeViewTests; 166 | productName = JHVerificationCodeViewTests; 167 | productReference = 088BF8C01F4FAF3C00B5863B /* JHVerificationCodeViewTests.xctest */; 168 | productType = "com.apple.product-type.bundle.unit-test"; 169 | }; 170 | /* End PBXNativeTarget section */ 171 | 172 | /* Begin PBXProject section */ 173 | 088BF89F1F4FAF3C00B5863B /* Project object */ = { 174 | isa = PBXProject; 175 | attributes = { 176 | LastUpgradeCheck = 0830; 177 | ORGANIZATIONNAME = HaoCold; 178 | TargetAttributes = { 179 | 088BF8A61F4FAF3C00B5863B = { 180 | CreatedOnToolsVersion = 8.3.2; 181 | DevelopmentTeam = D8MERC5W3E; 182 | ProvisioningStyle = Manual; 183 | }; 184 | 088BF8BF1F4FAF3C00B5863B = { 185 | CreatedOnToolsVersion = 8.3.2; 186 | ProvisioningStyle = Automatic; 187 | TestTargetID = 088BF8A61F4FAF3C00B5863B; 188 | }; 189 | }; 190 | }; 191 | buildConfigurationList = 088BF8A21F4FAF3C00B5863B /* Build configuration list for PBXProject "JHVerificationCodeView" */; 192 | compatibilityVersion = "Xcode 3.2"; 193 | developmentRegion = English; 194 | hasScannedForEncodings = 0; 195 | knownRegions = ( 196 | English, 197 | en, 198 | Base, 199 | ); 200 | mainGroup = 088BF89E1F4FAF3C00B5863B; 201 | productRefGroup = 088BF8A81F4FAF3C00B5863B /* Products */; 202 | projectDirPath = ""; 203 | projectRoot = ""; 204 | targets = ( 205 | 088BF8A61F4FAF3C00B5863B /* JHVerificationCodeView */, 206 | 088BF8BF1F4FAF3C00B5863B /* JHVerificationCodeViewTests */, 207 | ); 208 | }; 209 | /* End PBXProject section */ 210 | 211 | /* Begin PBXResourcesBuildPhase section */ 212 | 088BF8A51F4FAF3C00B5863B /* Resources */ = { 213 | isa = PBXResourcesBuildPhase; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | 088BF8BA1F4FAF3C00B5863B /* LaunchScreen.storyboard in Resources */, 217 | 088BF8B71F4FAF3C00B5863B /* Assets.xcassets in Resources */, 218 | 088BF8B51F4FAF3C00B5863B /* Main.storyboard in Resources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | 088BF8BE1F4FAF3C00B5863B /* Resources */ = { 223 | isa = PBXResourcesBuildPhase; 224 | buildActionMask = 2147483647; 225 | files = ( 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | }; 229 | /* End PBXResourcesBuildPhase section */ 230 | 231 | /* Begin PBXSourcesBuildPhase section */ 232 | 088BF8A31F4FAF3C00B5863B /* Sources */ = { 233 | isa = PBXSourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | 18EE78502507AA8000E7F10D /* NextViewController.m in Sources */, 237 | 088BF8B21F4FAF3C00B5863B /* ViewController.m in Sources */, 238 | 088BF8AF1F4FAF3C00B5863B /* AppDelegate.m in Sources */, 239 | 088BF8D21F4FAF7500B5863B /* JHVerificationCodeView.m in Sources */, 240 | 088BF8AC1F4FAF3C00B5863B /* main.m in Sources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | 088BF8BC1F4FAF3C00B5863B /* Sources */ = { 245 | isa = PBXSourcesBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | 088BF8C51F4FAF3C00B5863B /* JHVerificationCodeViewTests.m in Sources */, 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | }; 252 | /* End PBXSourcesBuildPhase section */ 253 | 254 | /* Begin PBXTargetDependency section */ 255 | 088BF8C21F4FAF3C00B5863B /* PBXTargetDependency */ = { 256 | isa = PBXTargetDependency; 257 | target = 088BF8A61F4FAF3C00B5863B /* JHVerificationCodeView */; 258 | targetProxy = 088BF8C11F4FAF3C00B5863B /* PBXContainerItemProxy */; 259 | }; 260 | /* End PBXTargetDependency section */ 261 | 262 | /* Begin PBXVariantGroup section */ 263 | 088BF8B31F4FAF3C00B5863B /* Main.storyboard */ = { 264 | isa = PBXVariantGroup; 265 | children = ( 266 | 088BF8B41F4FAF3C00B5863B /* Base */, 267 | ); 268 | name = Main.storyboard; 269 | sourceTree = ""; 270 | }; 271 | 088BF8B81F4FAF3C00B5863B /* LaunchScreen.storyboard */ = { 272 | isa = PBXVariantGroup; 273 | children = ( 274 | 088BF8B91F4FAF3C00B5863B /* Base */, 275 | ); 276 | name = LaunchScreen.storyboard; 277 | sourceTree = ""; 278 | }; 279 | /* End PBXVariantGroup section */ 280 | 281 | /* Begin XCBuildConfiguration section */ 282 | 088BF8C71F4FAF3C00B5863B /* Debug */ = { 283 | isa = XCBuildConfiguration; 284 | buildSettings = { 285 | ALWAYS_SEARCH_USER_PATHS = NO; 286 | CLANG_ANALYZER_NONNULL = YES; 287 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 288 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 289 | CLANG_CXX_LIBRARY = "libc++"; 290 | CLANG_ENABLE_MODULES = YES; 291 | CLANG_ENABLE_OBJC_ARC = YES; 292 | CLANG_WARN_BOOL_CONVERSION = YES; 293 | CLANG_WARN_CONSTANT_CONVERSION = YES; 294 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 295 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 296 | CLANG_WARN_EMPTY_BODY = YES; 297 | CLANG_WARN_ENUM_CONVERSION = YES; 298 | CLANG_WARN_INFINITE_RECURSION = YES; 299 | CLANG_WARN_INT_CONVERSION = YES; 300 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 301 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 302 | CLANG_WARN_UNREACHABLE_CODE = YES; 303 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 304 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 305 | COPY_PHASE_STRIP = NO; 306 | DEBUG_INFORMATION_FORMAT = dwarf; 307 | ENABLE_STRICT_OBJC_MSGSEND = YES; 308 | ENABLE_TESTABILITY = YES; 309 | GCC_C_LANGUAGE_STANDARD = gnu99; 310 | GCC_DYNAMIC_NO_PIC = NO; 311 | GCC_NO_COMMON_BLOCKS = YES; 312 | GCC_OPTIMIZATION_LEVEL = 0; 313 | GCC_PREPROCESSOR_DEFINITIONS = ( 314 | "DEBUG=1", 315 | "$(inherited)", 316 | ); 317 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 318 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 319 | GCC_WARN_UNDECLARED_SELECTOR = YES; 320 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 321 | GCC_WARN_UNUSED_FUNCTION = YES; 322 | GCC_WARN_UNUSED_VARIABLE = YES; 323 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 324 | MTL_ENABLE_DEBUG_INFO = YES; 325 | ONLY_ACTIVE_ARCH = YES; 326 | SDKROOT = iphoneos; 327 | TARGETED_DEVICE_FAMILY = "1,2"; 328 | }; 329 | name = Debug; 330 | }; 331 | 088BF8C81F4FAF3C00B5863B /* Release */ = { 332 | isa = XCBuildConfiguration; 333 | buildSettings = { 334 | ALWAYS_SEARCH_USER_PATHS = NO; 335 | CLANG_ANALYZER_NONNULL = YES; 336 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 337 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 338 | CLANG_CXX_LIBRARY = "libc++"; 339 | CLANG_ENABLE_MODULES = YES; 340 | CLANG_ENABLE_OBJC_ARC = YES; 341 | CLANG_WARN_BOOL_CONVERSION = YES; 342 | CLANG_WARN_CONSTANT_CONVERSION = YES; 343 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 344 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 345 | CLANG_WARN_EMPTY_BODY = YES; 346 | CLANG_WARN_ENUM_CONVERSION = YES; 347 | CLANG_WARN_INFINITE_RECURSION = YES; 348 | CLANG_WARN_INT_CONVERSION = YES; 349 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 350 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 351 | CLANG_WARN_UNREACHABLE_CODE = YES; 352 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 353 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 354 | COPY_PHASE_STRIP = NO; 355 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 356 | ENABLE_NS_ASSERTIONS = NO; 357 | ENABLE_STRICT_OBJC_MSGSEND = YES; 358 | GCC_C_LANGUAGE_STANDARD = gnu99; 359 | GCC_NO_COMMON_BLOCKS = YES; 360 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 361 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 362 | GCC_WARN_UNDECLARED_SELECTOR = YES; 363 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 364 | GCC_WARN_UNUSED_FUNCTION = YES; 365 | GCC_WARN_UNUSED_VARIABLE = YES; 366 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 367 | MTL_ENABLE_DEBUG_INFO = NO; 368 | SDKROOT = iphoneos; 369 | TARGETED_DEVICE_FAMILY = "1,2"; 370 | VALIDATE_PRODUCT = YES; 371 | }; 372 | name = Release; 373 | }; 374 | 088BF8CA1F4FAF3C00B5863B /* Debug */ = { 375 | isa = XCBuildConfiguration; 376 | buildSettings = { 377 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 378 | DEVELOPMENT_TEAM = D8MERC5W3E; 379 | INFOPLIST_FILE = JHVerificationCodeView/Info.plist; 380 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 381 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 382 | PRODUCT_BUNDLE_IDENTIFIER = com.haocold.JHVerificationCodeView; 383 | PRODUCT_NAME = "$(TARGET_NAME)"; 384 | PROVISIONING_PROFILE = "a6b55bc0-269a-40bc-8d1d-d2de538f4383"; 385 | PROVISIONING_PROFILE_SPECIFIER = haocold.develop; 386 | }; 387 | name = Debug; 388 | }; 389 | 088BF8CB1F4FAF3C00B5863B /* Release */ = { 390 | isa = XCBuildConfiguration; 391 | buildSettings = { 392 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 393 | DEVELOPMENT_TEAM = D8MERC5W3E; 394 | INFOPLIST_FILE = JHVerificationCodeView/Info.plist; 395 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 396 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 397 | PRODUCT_BUNDLE_IDENTIFIER = com.haocold.JHVerificationCodeView; 398 | PRODUCT_NAME = "$(TARGET_NAME)"; 399 | PROVISIONING_PROFILE = "a6b55bc0-269a-40bc-8d1d-d2de538f4383"; 400 | PROVISIONING_PROFILE_SPECIFIER = haocold.develop; 401 | }; 402 | name = Release; 403 | }; 404 | 088BF8CD1F4FAF3C00B5863B /* Debug */ = { 405 | isa = XCBuildConfiguration; 406 | buildSettings = { 407 | BUNDLE_LOADER = "$(TEST_HOST)"; 408 | INFOPLIST_FILE = JHVerificationCodeViewTests/Info.plist; 409 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 410 | PRODUCT_BUNDLE_IDENTIFIER = com.haocold.JHVerificationCodeViewTests; 411 | PRODUCT_NAME = "$(TARGET_NAME)"; 412 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JHVerificationCodeView.app/JHVerificationCodeView"; 413 | }; 414 | name = Debug; 415 | }; 416 | 088BF8CE1F4FAF3C00B5863B /* Release */ = { 417 | isa = XCBuildConfiguration; 418 | buildSettings = { 419 | BUNDLE_LOADER = "$(TEST_HOST)"; 420 | INFOPLIST_FILE = JHVerificationCodeViewTests/Info.plist; 421 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 422 | PRODUCT_BUNDLE_IDENTIFIER = com.haocold.JHVerificationCodeViewTests; 423 | PRODUCT_NAME = "$(TARGET_NAME)"; 424 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JHVerificationCodeView.app/JHVerificationCodeView"; 425 | }; 426 | name = Release; 427 | }; 428 | /* End XCBuildConfiguration section */ 429 | 430 | /* Begin XCConfigurationList section */ 431 | 088BF8A21F4FAF3C00B5863B /* Build configuration list for PBXProject "JHVerificationCodeView" */ = { 432 | isa = XCConfigurationList; 433 | buildConfigurations = ( 434 | 088BF8C71F4FAF3C00B5863B /* Debug */, 435 | 088BF8C81F4FAF3C00B5863B /* Release */, 436 | ); 437 | defaultConfigurationIsVisible = 0; 438 | defaultConfigurationName = Release; 439 | }; 440 | 088BF8C91F4FAF3C00B5863B /* Build configuration list for PBXNativeTarget "JHVerificationCodeView" */ = { 441 | isa = XCConfigurationList; 442 | buildConfigurations = ( 443 | 088BF8CA1F4FAF3C00B5863B /* Debug */, 444 | 088BF8CB1F4FAF3C00B5863B /* Release */, 445 | ); 446 | defaultConfigurationIsVisible = 0; 447 | defaultConfigurationName = Release; 448 | }; 449 | 088BF8CC1F4FAF3C00B5863B /* Build configuration list for PBXNativeTarget "JHVerificationCodeViewTests" */ = { 450 | isa = XCConfigurationList; 451 | buildConfigurations = ( 452 | 088BF8CD1F4FAF3C00B5863B /* Debug */, 453 | 088BF8CE1F4FAF3C00B5863B /* Release */, 454 | ); 455 | defaultConfigurationIsVisible = 0; 456 | defaultConfigurationName = Release; 457 | }; 458 | /* End XCConfigurationList section */ 459 | }; 460 | rootObject = 088BF89F1F4FAF3C00B5863B /* Project object */; 461 | } 462 | --------------------------------------------------------------------------------