├── .gitignore ├── CYPasswordView.podspec ├── CYPasswordView ├── .DS_Store ├── CYConst.h ├── CYConst.m ├── CYPasswordInputView.h ├── CYPasswordInputView.m ├── CYPasswordView.bundle │ ├── password_background@2x.png │ ├── password_close@2x.png │ ├── password_error@2x.png │ ├── password_loading_a@2x.png │ ├── password_loading_b@2x.png │ ├── password_point@2x.png │ ├── password_success@2x.png │ └── password_textfield@2x.png ├── CYPasswordView.h ├── CYPasswordView.m ├── NSBundle+CYPasswordView.h ├── NSBundle+CYPasswordView.m ├── UIDevice+Extension.h ├── UIDevice+Extension.m ├── UIView+Extension.h └── UIView+Extension.m ├── CYPasswordViewDemo ├── .DS_Store ├── CYPasswordViewDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── CYPasswordViewDemo │ ├── .DS_Store │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ └── arrow.imageset │ │ ├── Contents.json │ │ └── account_next@2x.png │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── CYPasswordViewDemo.gif │ ├── Info.plist │ ├── MBProgressHUD │ ├── MBProgressHUD+MJ.h │ ├── MBProgressHUD+MJ.m │ ├── MBProgressHUD.bundle │ │ ├── error.png │ │ ├── error@2x.png │ │ ├── success.png │ │ └── success@2x.png │ ├── MBProgressHUD.h │ └── MBProgressHUD.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── LICENSE └── README.md /.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 | -------------------------------------------------------------------------------- /CYPasswordView.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint CYPasswordView.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | s.name = "CYPasswordView" 12 | s.version = "0.0.4" 13 | s.authors = { 'chernyog' => 'chenyios@126.com' } 14 | s.summary = "CYPasswordView 是一个模仿支付宝输入支付密码的密码框。" 15 | s.homepage = "https://github.com/chernyog/CYPasswordView" 16 | s.license = { :type => "MIT", :file => "LICENSE" } 17 | s.author = { "cheny" => "yong.chen@jimubox.com" } 18 | s.platform = :ios, "8.0" 19 | s.source = { :git => "https://github.com/chernyog/CYPasswordView.git", :tag => "0.0.4" } 20 | s.source_files = "CYPasswordView/**/*.{h,m}" 21 | s.public_header_files = "CYPasswordView/*.h" 22 | s.resources = "CYPasswordView/CYPasswordView.bundle" 23 | s.requires_arc = true 24 | 25 | end 26 | -------------------------------------------------------------------------------- /CYPasswordView/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordView/.DS_Store -------------------------------------------------------------------------------- /CYPasswordView/CYConst.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | // 日志输出 4 | #ifdef DEBUG 5 | #define CYLog(...) NSLog(__VA_ARGS__) 6 | #else 7 | #define CYLog(...) 8 | #endif 9 | 10 | // RGB颜色 11 | #define CYColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0] 12 | #define CYColor_A(r, g, b, a) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:(a)] 13 | 14 | // 字体大小 15 | #define CYLabelFont [UIFont boldSystemFontOfSize:13] 16 | #define CYFont(f) [UIFont systemFontOfSize:(f)] 17 | #define CYFontB(f) [UIFont boldSystemFontOfSize:(f)] 18 | 19 | // 图片路径 20 | //#define CYPasswordViewSrcName(file) [@"CYPasswordView.bundle" stringByAppendingPathComponent:file] 21 | 22 | /** 屏幕的宽高 */ 23 | #define CYScreen [UIScreen mainScreen] 24 | #define CYScreenWith CYScreen.bounds.size.width 25 | #define CYScreenHeight CYScreen.bounds.size.height 26 | 27 | #define CYNotificationCenter [NSNotificationCenter defaultCenter] 28 | 29 | // 常量 30 | /** 密码框的高度 */ 31 | UIKIT_EXTERN const CGFloat CYPasswordInputViewHeight; 32 | /** 密码框标题的高度 */ 33 | UIKIT_EXTERN const CGFloat CYPasswordViewTitleHeight; 34 | /** 密码框显示或隐藏时间 */ 35 | UIKIT_EXTERN const CGFloat CYPasswordViewAnimationDuration; 36 | /** 关闭按钮的宽高 */ 37 | UIKIT_EXTERN const CGFloat CYPasswordViewCloseButtonWH; 38 | /** 关闭按钮的左边距 */ 39 | UIKIT_EXTERN const CGFloat CYPasswordViewCloseButtonMarginLeft; 40 | /** 输入点的宽高 */ 41 | UIKIT_EXTERN const CGFloat CYPasswordViewPointnWH; 42 | /** TextField图片的宽 */ 43 | UIKIT_EXTERN const CGFloat CYPasswordViewTextFieldWidth; 44 | /** TextField图片的高 */ 45 | UIKIT_EXTERN const CGFloat CYPasswordViewTextFieldHeight; 46 | /** TextField图片向上间距 */ 47 | UIKIT_EXTERN const CGFloat CYPasswordViewTextFieldMarginTop; 48 | /** 忘记密码按钮向上间距 */ 49 | UIKIT_EXTERN const CGFloat CYPasswordViewForgetPWDButtonMarginTop; 50 | 51 | UIKIT_EXTERN NSString *const CYPasswordViewKeyboardNumberKey; 52 | 53 | // 通知 54 | UIKIT_EXTERN NSString *const CYPasswordViewCancleButtonClickNotification; 55 | UIKIT_EXTERN NSString *const CYPasswordViewDeleteButtonClickNotification; 56 | UIKIT_EXTERN NSString *const CYPasswordViewNumberButtonClickNotification; 57 | UIKIT_EXTERN NSString *const CYPasswordViewForgetPWDButtonClickNotification; 58 | UIKIT_EXTERN NSString *const CYPasswordViewEnabledUserInteractionNotification; 59 | UIKIT_EXTERN NSString *const CYPasswordViewDisEnabledUserInteractionNotification; 60 | -------------------------------------------------------------------------------- /CYPasswordView/CYConst.m: -------------------------------------------------------------------------------- 1 | 2 | #import "CYConst.h" 3 | 4 | // 常量 5 | const CGFloat CYPasswordInputViewHeight = (196 + 216); 6 | const CGFloat CYPasswordViewTitleHeight = 55; 7 | const CGFloat CYPasswordViewAnimationDuration = 0.25; 8 | const CGFloat CYPasswordViewCloseButtonWH = 55; 9 | const CGFloat CYPasswordViewCloseButtonMarginLeft = 0; 10 | const CGFloat CYPasswordViewPointnWH = 10; 11 | const CGFloat CYPasswordViewTextFieldWidth = 297; 12 | const CGFloat CYPasswordViewTextFieldHeight = 50; 13 | const CGFloat CYPasswordViewTextFieldMarginTop = 25; 14 | const CGFloat CYPasswordViewForgetPWDButtonMarginTop = 12; 15 | 16 | NSString *const CYPasswordViewKeyboardNumberKey = @"CYPasswordViewKeyboardNumberKey"; 17 | 18 | // 通知 19 | NSString *const CYPasswordViewCancleButtonClickNotification = @"CYPasswordViewCancleButtonClickNotification"; 20 | NSString *const CYPasswordViewDeleteButtonClickNotification = @"CYPasswordViewDeleteButtonClickNotification"; 21 | NSString *const CYPasswordViewNumberButtonClickNotification = @"CYPasswordViewNumberButtonClickNotification"; 22 | NSString *const CYPasswordViewForgetPWDButtonClickNotification = @"CYPasswordViewForgetPWDButtonClickNotification"; 23 | NSString *const CYPasswordViewEnabledUserInteractionNotification = @"CYPasswordViewEnabledUserInteractionNotification"; 24 | NSString *const CYPasswordViewDisEnabledUserInteractionNotification = @"CYPasswordViewDisEnabledUserInteractionNotification"; 25 | -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordInputView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CYPasswordInputView.h 3 | // CYPasswordViewDemo 4 | // 5 | // Created by cheny on 15/10/8. 6 | // Copyright © 2015年 zhssit. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CYPasswordInputView : UIView 12 | 13 | @property (nonatomic, copy) NSString *title; 14 | 15 | @end -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordInputView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CYPasswordInputView.m 3 | // CYPasswordViewDemo 4 | // 5 | // Created by cheny on 15/10/8. 6 | // Copyright © 2015年 zhssit. All rights reserved. 7 | // 8 | 9 | #import "CYPasswordInputView.h" 10 | #import "CYConst.h" 11 | #import "UIView+Extension.h" 12 | #import "NSBundle+CYPasswordView.h" 13 | 14 | #define kNumCount 6 15 | 16 | @interface CYPasswordInputView () 17 | 18 | /** 保存用户输入的数字集合 */ 19 | @property (nonatomic, strong) NSMutableArray *inputNumArray; 20 | /** 关闭按钮 */ 21 | @property (nonatomic, weak) UIButton *btnClose; 22 | /** 忘记密码 */ 23 | @property (nonatomic, weak) UIButton *btnForgetPWD; 24 | 25 | @end 26 | 27 | @implementation CYPasswordInputView 28 | 29 | #pragma mark - 生命周期方法 30 | - (instancetype)initWithFrame:(CGRect)frame 31 | { 32 | if (self = [super initWithFrame:frame]) { 33 | self.backgroundColor = [UIColor clearColor]; 34 | /** 注册通知 */ 35 | [self setupNotification]; 36 | /** 添加子控件 */ 37 | [self setupSubViews]; 38 | } 39 | return self; 40 | } 41 | 42 | - (void)layoutSubviews 43 | { 44 | [super layoutSubviews]; 45 | // 设置关闭按钮的坐标 46 | self.btnClose.width = CYPasswordViewCloseButtonWH; 47 | self.btnClose.height = CYPasswordViewCloseButtonWH; 48 | self.btnClose.x = CYPasswordViewCloseButtonMarginLeft; 49 | self.btnClose.centerY = CYPasswordViewTitleHeight * 0.5; 50 | 51 | // 设置忘记密码按钮的坐标 52 | self.btnForgetPWD.x = CYScreenWith - (CYScreenWith - CYPasswordViewTextFieldWidth) * 0.5 - self.btnForgetPWD.width; 53 | self.btnForgetPWD.y = CYPasswordViewTitleHeight + CYPasswordViewTextFieldMarginTop + CYPasswordViewTextFieldHeight + CYPasswordViewForgetPWDButtonMarginTop; 54 | } 55 | 56 | - (void)dealloc 57 | { 58 | CYLog(@"cy =========== %@:我走了", [self class]); 59 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 60 | } 61 | 62 | /** 添加子控件 */ 63 | - (void)setupSubViews 64 | { 65 | /** 关闭按钮 */ 66 | UIButton *btnCancel = [UIButton buttonWithType:UIButtonTypeCustom]; 67 | [self addSubview:btnCancel]; 68 | [btnCancel setBackgroundImage:[NSBundle cy_closeImage] forState:UIControlStateNormal]; 69 | [btnCancel setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal]; 70 | self.btnClose = btnCancel; 71 | [self.btnClose addTarget:self action:@selector(btnClose_Click:) forControlEvents:UIControlEventTouchUpInside]; 72 | 73 | /** 忘记密码按钮 */ 74 | UIButton *btnForgetPWD = [UIButton buttonWithType:UIButtonTypeCustom]; 75 | [self addSubview:btnForgetPWD]; 76 | [btnForgetPWD setTitle:@"忘记密码?" forState:UIControlStateNormal]; 77 | [btnForgetPWD setTitleColor:CYColor(0, 125, 227) forState:UIControlStateNormal]; 78 | btnForgetPWD.titleLabel.font = CYFont(13); 79 | [btnForgetPWD sizeToFit]; 80 | self.btnForgetPWD = btnForgetPWD; 81 | [self.btnForgetPWD addTarget:self action:@selector(btnForgetPWD_Click:) forControlEvents:UIControlEventTouchUpInside]; 82 | } 83 | 84 | /** 注册通知 */ 85 | - (void)setupNotification { 86 | // 用户按下删除键通知 87 | [CYNotificationCenter addObserver:self selector:@selector(delete) name:CYPasswordViewDeleteButtonClickNotification object:nil]; 88 | // 用户按下数字键通知 89 | [CYNotificationCenter addObserver:self selector:@selector(number:) name:CYPasswordViewNumberButtonClickNotification object:nil]; 90 | [CYNotificationCenter addObserver:self selector:@selector(disEnalbeCloseButton:) name:CYPasswordViewDisEnabledUserInteractionNotification object:nil]; 91 | [CYNotificationCenter addObserver:self selector:@selector(disEnalbeCloseButton:) name:CYPasswordViewEnabledUserInteractionNotification object:nil]; 92 | } 93 | 94 | // 按钮点击 95 | - (void)btnClose_Click:(UIButton *)sender { 96 | [CYNotificationCenter postNotificationName:CYPasswordViewCancleButtonClickNotification object:self]; 97 | [self.inputNumArray removeAllObjects]; 98 | } 99 | 100 | - (void)btnForgetPWD_Click:(UIButton *)sender { 101 | [CYNotificationCenter postNotificationName:CYPasswordViewForgetPWDButtonClickNotification object:self]; 102 | } 103 | 104 | - (void) disEnalbeCloseButton:(NSNotification *)notification{ 105 | BOOL flag = [[notification.object valueForKeyPath:@"enable"] boolValue]; 106 | self.btnClose.userInteractionEnabled = flag; 107 | self.btnForgetPWD.userInteractionEnabled = flag; 108 | } 109 | 110 | - (void)drawRect:(CGRect)rect { 111 | // 画图 112 | UIImage *imgBackground = [NSBundle cy_backgroundImage]; 113 | UIImage *imgTextfield = [NSBundle cy_textfieldImage]; 114 | 115 | [imgBackground drawInRect:rect]; 116 | 117 | CGFloat textfieldY = CYPasswordViewTitleHeight + CYPasswordViewTextFieldMarginTop; 118 | CGFloat textfieldW = CYPasswordViewTextFieldWidth; 119 | CGFloat textfieldX = (CYScreenWith - textfieldW) * 0.5; 120 | CGFloat textfieldH = CYPasswordViewTextFieldHeight; 121 | [imgTextfield drawInRect:CGRectMake(textfieldX, textfieldY, textfieldW, textfieldH)]; 122 | 123 | // 画标题 124 | NSString *title = self.title ? self.title : @"输入交易密码"; 125 | 126 | NSDictionary *arrts = @{NSFontAttributeName:CYFontB(18)}; 127 | CGSize size = [title boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:arrts context:nil].size; 128 | CGFloat titleW = size.width; 129 | CGFloat titleH = size.height; 130 | CGFloat titleX = (self.width - titleW) * 0.5; 131 | CGFloat titleY = (CYPasswordViewTitleHeight - titleH) * 0.5; 132 | CGRect titleRect = CGRectMake(titleX, titleY, titleW, titleH); 133 | 134 | NSMutableDictionary *attr = [NSMutableDictionary dictionary]; 135 | attr[NSFontAttributeName] = CYFontB(18); 136 | attr[NSForegroundColorAttributeName] = CYColor(102, 102, 102); 137 | [title drawInRect:titleRect withAttributes:attr]; 138 | 139 | // 画点 140 | UIImage *pointImage = [NSBundle cy_pointImage]; 141 | CGFloat pointW = CYPasswordViewPointnWH; 142 | CGFloat pointH = CYPasswordViewPointnWH; 143 | CGFloat pointY = textfieldY + (textfieldH - pointH) * 0.5; 144 | __block CGFloat pointX; 145 | 146 | // 一个格子的宽度 147 | CGFloat cellW = textfieldW / kNumCount; 148 | CGFloat padding = (cellW - pointW) * 0.5; 149 | [self.inputNumArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 150 | pointX = textfieldX + (2 * idx + 1) * padding + idx * pointW; 151 | [pointImage drawInRect:CGRectMake(pointX, pointY, pointW, pointH)]; 152 | }]; 153 | } 154 | 155 | #pragma mark - 懒加载 156 | - (NSMutableArray *)inputNumArray { 157 | if (_inputNumArray == nil) { 158 | _inputNumArray = [NSMutableArray array]; 159 | } 160 | return _inputNumArray; 161 | } 162 | 163 | #pragma mark - 私有方法 164 | // 响应用户按下删除键事件 165 | - (void)delete { 166 | [self.inputNumArray removeLastObject]; 167 | [self setNeedsDisplay]; 168 | } 169 | 170 | // 响应用户按下数字键事件 171 | - (void)number:(NSNotification *)note { 172 | NSDictionary *userInfo = note.userInfo; 173 | NSString *numObj = userInfo[CYPasswordViewKeyboardNumberKey]; 174 | if (numObj.length >= kNumCount) return; 175 | [self.inputNumArray addObject:numObj]; 176 | [self setNeedsDisplay]; 177 | } 178 | 179 | @end 180 | -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordView.bundle/password_background@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordView/CYPasswordView.bundle/password_background@2x.png -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordView.bundle/password_close@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordView/CYPasswordView.bundle/password_close@2x.png -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordView.bundle/password_error@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordView/CYPasswordView.bundle/password_error@2x.png -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordView.bundle/password_loading_a@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordView/CYPasswordView.bundle/password_loading_a@2x.png -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordView.bundle/password_loading_b@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordView/CYPasswordView.bundle/password_loading_b@2x.png -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordView.bundle/password_point@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordView/CYPasswordView.bundle/password_point@2x.png -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordView.bundle/password_success@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordView/CYPasswordView.bundle/password_success@2x.png -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordView.bundle/password_textfield@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordView/CYPasswordView.bundle/password_textfield@2x.png -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CYPasswordView.h 3 | // CYPasswordViewDemo 4 | // 5 | // Created by cheny on 15/10/8. 6 | // Copyright © 2015年 zhssit. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CYPasswordInputView.h" 11 | #import "CYConst.h" 12 | #import "NSBundle+CYPasswordView.h" 13 | 14 | @interface CYPasswordView : UIView 15 | 16 | /** 正在请求时显示的文本 */ 17 | @property (nonatomic, copy) NSString *loadingText; 18 | 19 | /** 完成的回调block */ 20 | @property (nonatomic, copy) void (^finish) (NSString *password); 21 | 22 | /** 密码框的标题 */ 23 | @property (nonatomic, copy) NSString *title; 24 | 25 | /** 弹出密码框 */ 26 | - (void)showInView:(UIView *)view; 27 | 28 | /** 隐藏键盘 */ 29 | - (void)hideKeyboard; 30 | 31 | /** 隐藏密码框 */ 32 | - (void)hide; 33 | 34 | /** 开始加载 */ 35 | - (void)startLoading; 36 | 37 | /** 加载完成 */ 38 | - (void)stopLoading; 39 | 40 | /** 请求完成 */ 41 | - (void)requestComplete:(BOOL)state; 42 | - (void)requestComplete:(BOOL)state message:(NSString *)message; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /CYPasswordView/CYPasswordView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CYPasswordView.m 3 | // CYPasswordViewDemo 4 | // 5 | // Created by cheny on 15/10/8. 6 | // Copyright © 2015年 zhssit. All rights reserved. 7 | // 8 | 9 | #import "CYPasswordView.h" 10 | #import "UIView+Extension.h" 11 | #import "UIDevice+Extension.h" 12 | 13 | #define kPWDLength 6 14 | 15 | @interface CYPasswordView () 16 | 17 | /** 输入框 */ 18 | @property (nonatomic, strong) CYPasswordInputView *passwordInputView; 19 | @property (nonatomic, strong) UITextField *txfResponsder; 20 | 21 | /** 蒙板 */ 22 | @property (nonatomic, strong) UIControl *coverView; 23 | /** 返回密码 */ 24 | @property (nonatomic, copy) NSString *password; 25 | 26 | @property (nonatomic, strong) UIImageView *imgRotation; 27 | @property (nonatomic, strong) UILabel *lblMessage; 28 | 29 | @end 30 | 31 | @implementation CYPasswordView 32 | 33 | #pragma mark - 常量区 34 | static NSString *tempStr; 35 | 36 | #pragma mark - 生命周期方法 37 | - (instancetype)initWithFrame:(CGRect)frame 38 | { 39 | self = [super initWithFrame:CYScreen.bounds]; 40 | if (self) { 41 | [self setupUI]; 42 | } 43 | return self; 44 | } 45 | 46 | - (void)dealloc 47 | { 48 | CYLog(@"cy =========== %@:我走了", [self class]); 49 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 50 | } 51 | 52 | - (void)setupUI { 53 | self.backgroundColor = [UIColor clearColor]; 54 | // 蒙版 55 | [self addSubview:self.coverView]; 56 | // 输入框 57 | [self addSubview:self.passwordInputView]; 58 | // 响应者 59 | [self addSubview:self.txfResponsder]; 60 | 61 | [self.passwordInputView addSubview:self.imgRotation]; 62 | [self.passwordInputView addSubview:self.lblMessage]; 63 | } 64 | 65 | - (void)layoutSubviews { 66 | [super layoutSubviews]; 67 | self.imgRotation.centerX = self.passwordInputView.centerX; 68 | self.imgRotation.centerY = self.passwordInputView.height * 0.5; 69 | 70 | self.lblMessage.centerX = self.passwordInputView.centerX; 71 | self.lblMessage.centerY = CGRectGetMaxY(self.imgRotation.frame) + CYPasswordViewTextFieldMarginTop; 72 | self.lblMessage.x = 0; 73 | self.lblMessage.width = CYScreenWith; 74 | } 75 | 76 | #pragma mark - 77 | #pragma mark 处理字符串 和 删除键 78 | - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { 79 | if (!tempStr) { 80 | tempStr = string; 81 | } else { 82 | tempStr = [NSString stringWithFormat:@"%@%@",tempStr,string]; 83 | } 84 | 85 | if ([string isEqualToString:@""]) { 86 | [CYNotificationCenter postNotificationName:CYPasswordViewDeleteButtonClickNotification object:self]; 87 | if (tempStr.length > 0) { // 删除最后一个字符串 88 | NSString *lastStr = [tempStr substringToIndex:[tempStr length] - 1]; 89 | tempStr = lastStr; 90 | } 91 | } else { 92 | if (tempStr.length == kPWDLength) { 93 | if (self.finish) { 94 | self.finish(tempStr); 95 | self.finish = nil; 96 | } 97 | tempStr = nil; 98 | } 99 | NSMutableDictionary *userInfoDict = [NSMutableDictionary dictionary]; 100 | userInfoDict[CYPasswordViewKeyboardNumberKey] = string; 101 | [CYNotificationCenter postNotificationName:CYPasswordViewNumberButtonClickNotification object:self userInfo:userInfoDict]; 102 | } 103 | return YES; 104 | } 105 | 106 | /** 输入框的取消按钮点击 */ 107 | - (void)cancle 108 | { 109 | [self hideKeyboard:^(BOOL finished) { 110 | self.inputView.hidden = YES; 111 | tempStr = nil; 112 | [self removeFromSuperview]; 113 | [self hideKeyboard:nil]; 114 | [self.inputView setNeedsDisplay]; 115 | }]; 116 | } 117 | 118 | #pragma mark - 公开方法 119 | // 关闭键盘 120 | - (void)hideKeyboard 121 | { 122 | [self hideKeyboard:nil]; 123 | } 124 | 125 | - (void)hide { 126 | [self removeFromSuperview]; 127 | } 128 | 129 | - (void)showInView:(UIView *)view 130 | { 131 | [view addSubview:self]; 132 | /** 输入框起始frame */ 133 | self.passwordInputView.height = CYPasswordInputViewHeight + UIDevice.safeAreaInsets.bottom * 2; 134 | self.passwordInputView.y = self.height; 135 | self.passwordInputView.width = CYScreenWith; 136 | self.passwordInputView.x = 0; 137 | /** 弹出键盘 */ 138 | [self showKeyboard]; 139 | } 140 | 141 | - (void)startLoading { 142 | [self startRotation:self.imgRotation]; 143 | [CYNotificationCenter postNotificationName:CYPasswordViewDisEnabledUserInteractionNotification object:@{@"enable":@(NO)}]; 144 | } 145 | 146 | - (void)stopLoading { 147 | [self stopRotation:self.imgRotation]; 148 | [CYNotificationCenter postNotificationName:CYPasswordViewEnabledUserInteractionNotification object:@{@"enable":@(YES)}]; 149 | } 150 | 151 | - (void)requestComplete:(BOOL)state { 152 | if (state) { 153 | [self requestComplete:state message:@"支付成功"]; 154 | } else { 155 | [self requestComplete:state message:@"支付失败"]; 156 | } 157 | } 158 | - (void)requestComplete:(BOOL)state message:(NSString *)message { 159 | if (state) { 160 | // 请求成功 161 | self.lblMessage.text = message; 162 | self.imgRotation.image = [NSBundle cy_successImage]; 163 | } else { 164 | // 请求失败 165 | self.lblMessage.text = message; 166 | self.imgRotation.image = [NSBundle cy_errorImage]; 167 | } 168 | } 169 | 170 | #pragma mark - 私有方法 171 | /** 键盘弹出 */ 172 | - (void)showKeyboard { 173 | [self.txfResponsder becomeFirstResponder]; 174 | [UIView animateWithDuration:CYPasswordViewAnimationDuration delay:0 options:UIViewAnimationOptionTransitionNone animations:^{ 175 | self.passwordInputView.y = (self.height - self.passwordInputView.height); 176 | } completion:^(BOOL finished) { 177 | CYLog(@"%@", NSStringFromCGRect(self.passwordInputView.frame)); 178 | }]; 179 | } 180 | 181 | /** 键盘退下 */ 182 | - (void)hideKeyboard:(void (^)(BOOL finished))completion { 183 | [self.txfResponsder endEditing:NO]; 184 | [UIView animateWithDuration:CYPasswordViewAnimationDuration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 185 | self.inputView.transform = CGAffineTransformIdentity; 186 | } completion:completion]; 187 | } 188 | 189 | /** 190 | * 开始旋转 191 | */ 192 | - (void)startRotation:(UIView *)view { 193 | _imgRotation.hidden = NO; 194 | _lblMessage.hidden = NO; 195 | CABasicAnimation* rotationAnimation; 196 | rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; 197 | rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 ]; 198 | rotationAnimation.duration = 2.0; 199 | rotationAnimation.cumulative = YES; 200 | rotationAnimation.repeatCount = MAXFLOAT; 201 | [view.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"]; 202 | } 203 | 204 | /** 205 | * 结束旋转 206 | */ 207 | - (void)stopRotation:(UIView *)view { 208 | // _imgRotation.hidden = YES; 209 | // _lblMessage.hidden = YES; 210 | [view.layer removeAllAnimations]; 211 | } 212 | 213 | #pragma mark - Set 方法 214 | - (void)setTitle:(NSString *)title { 215 | _title = [title copy]; 216 | self.passwordInputView.title = title; 217 | } 218 | 219 | - (void)setLoadingText:(NSString *)loadingText { 220 | _loadingText = [loadingText copy]; 221 | self.lblMessage.text = loadingText; 222 | } 223 | 224 | #pragma mark - 懒加载 225 | - (UIControl *)coverView 226 | { 227 | if (_coverView == nil) 228 | { 229 | _coverView = [[UIControl alloc] init]; 230 | [_coverView setBackgroundColor:[UIColor blackColor]]; 231 | _coverView.alpha = 0.4; 232 | _coverView.frame = self.bounds; 233 | } 234 | return _coverView; 235 | } 236 | 237 | - (CYPasswordInputView *)passwordInputView 238 | { 239 | if (_passwordInputView == nil) 240 | { 241 | _passwordInputView = [[CYPasswordInputView alloc] init]; 242 | /** 注册取消按钮点击的通知 */ 243 | [CYNotificationCenter addObserver:self selector:@selector(cancle) name:CYPasswordViewCancleButtonClickNotification object:nil]; 244 | } 245 | return _passwordInputView; 246 | } 247 | 248 | - (UITextField *)txfResponsder 249 | { 250 | if (_txfResponsder == nil) 251 | { 252 | _txfResponsder = [[UITextField alloc] init]; 253 | _txfResponsder.delegate = self; 254 | _txfResponsder.keyboardType = UIKeyboardTypeNumberPad; 255 | _txfResponsder.secureTextEntry = YES; 256 | } 257 | return _txfResponsder; 258 | } 259 | 260 | - (UIImageView *)imgRotation { 261 | if (_imgRotation == nil) { 262 | _imgRotation = [[UIImageView alloc] init]; 263 | _imgRotation.image = [NSBundle cy_loadingImage]; 264 | [_imgRotation sizeToFit]; 265 | _imgRotation.hidden = YES; 266 | } 267 | return _imgRotation; 268 | } 269 | 270 | - (UILabel *)lblMessage { 271 | if (_lblMessage == nil) { 272 | _lblMessage = [[UILabel alloc] init]; 273 | _lblMessage.text = @"支付中..."; 274 | _lblMessage.hidden = YES; 275 | _lblMessage.textColor = [UIColor darkGrayColor]; 276 | _lblMessage.font = CYLabelFont; 277 | _lblMessage.textAlignment = NSTextAlignmentCenter; 278 | [_lblMessage sizeToFit]; 279 | } 280 | return _lblMessage; 281 | } 282 | 283 | @end 284 | -------------------------------------------------------------------------------- /CYPasswordView/NSBundle+CYPasswordView.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSBundle+NSBundle_CYPasswordView.h 3 | // CYPasswordViewDemo 4 | // 5 | // Created by apple on 2017/9/8. 6 | // Copyright © 2017年 zhssit. All rights reserved. 7 | // 借鉴自:MJRefresh 8 | 9 | #import 10 | 11 | @interface NSBundle (NSBundle_CYPasswordView) 12 | + (instancetype)cy_passwordViewBundle; 13 | + (UIImage *)cy_closeImage; 14 | + (UIImage *)cy_backgroundImage; 15 | + (UIImage *)cy_textfieldImage; 16 | + (UIImage *)cy_pointImage; 17 | + (UIImage *)cy_successImage; 18 | + (UIImage *)cy_errorImage; 19 | + (UIImage *)cy_loadingImage; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /CYPasswordView/NSBundle+CYPasswordView.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSBundle+NSBundle_CYPasswordView.m 3 | // CYPasswordViewDemo 4 | // 5 | // Created by apple on 2017/9/8. 6 | // Copyright © 2017年 zhssit. All rights reserved. 7 | // 8 | 9 | #import "NSBundle+CYPasswordView.h" 10 | #import "CYPasswordView.h" 11 | 12 | @implementation NSBundle (NSBundle_CYPasswordView) 13 | + (instancetype)cy_passwordViewBundle 14 | { 15 | static NSBundle *refreshBundle = nil; 16 | if (refreshBundle == nil) { 17 | // 这里不使用mainBundle是为了适配pod 1.x和0.x 18 | refreshBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[CYPasswordView class]] pathForResource:@"CYPasswordView" ofType:@"bundle"]]; 19 | } 20 | return refreshBundle; 21 | } 22 | 23 | + (UIImage *)cy_closeImage { 24 | static UIImage *_image = nil; 25 | if (_image == nil) { 26 | _image = [[UIImage imageWithContentsOfFile:[[self cy_passwordViewBundle] pathForResource:@"password_close@2x" ofType:@"png"]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 27 | } 28 | return _image; 29 | } 30 | + (UIImage *)cy_backgroundImage { 31 | static UIImage *_image = nil; 32 | if (_image == nil) { 33 | _image = [[UIImage imageWithContentsOfFile:[[self cy_passwordViewBundle] pathForResource:@"password_background@2x" ofType:@"png"]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 34 | } 35 | return _image; 36 | } 37 | + (UIImage *)cy_textfieldImage { 38 | static UIImage *_image = nil; 39 | if (_image == nil) { 40 | _image = [[UIImage imageWithContentsOfFile:[[self cy_passwordViewBundle] pathForResource:@"password_textfield@2x" ofType:@"png"]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 41 | } 42 | return _image; 43 | } 44 | + (UIImage *)cy_pointImage { 45 | static UIImage *_image = nil; 46 | if (_image == nil) { 47 | _image = [[UIImage imageWithContentsOfFile:[[self cy_passwordViewBundle] pathForResource:@"password_point@2x" ofType:@"png"]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 48 | } 49 | return _image; 50 | } 51 | + (UIImage *)cy_successImage { 52 | static UIImage *_image = nil; 53 | if (_image == nil) { 54 | _image = [[UIImage imageWithContentsOfFile:[[self cy_passwordViewBundle] pathForResource:@"password_success@2x" ofType:@"png"]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 55 | } 56 | return _image; 57 | } 58 | + (UIImage *)cy_errorImage { 59 | static UIImage *_image = nil; 60 | if (_image == nil) { 61 | _image = [[UIImage imageWithContentsOfFile:[[self cy_passwordViewBundle] pathForResource:@"password_error@2x" ofType:@"png"]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 62 | } 63 | return _image; 64 | } 65 | + (UIImage *)cy_loadingImage { 66 | static UIImage *_image = nil; 67 | if (_image == nil) { 68 | _image = [[UIImage imageWithContentsOfFile:[[self cy_passwordViewBundle] pathForResource:@"password_loading_a@2x" ofType:@"png"]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 69 | } 70 | return _image; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /CYPasswordView/UIDevice+Extension.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIDevice+Extension.h 3 | // CYPasswordViewDemo 4 | // 5 | // Created by yong.chen on 2020/9/21. 6 | // Copyright © 2020 zhssit. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface UIDevice (Extension) 14 | + (UIEdgeInsets)safeAreaInsets; 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /CYPasswordView/UIDevice+Extension.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIDevice+Extension.m 3 | // CYPasswordViewDemo 4 | // 5 | // Created by yong.chen on 2020/9/21. 6 | // Copyright © 2020 zhssit. All rights reserved. 7 | // 8 | 9 | #import "UIDevice+Extension.h" 10 | 11 | @implementation UIDevice (Extension) 12 | + (UIEdgeInsets)safeAreaInsets { 13 | if (@available(iOS 11.0, *)) { 14 | return UIApplication.sharedApplication.keyWindow.safeAreaInsets; 15 | } 16 | return UIEdgeInsetsZero; 17 | } 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /CYPasswordView/UIView+Extension.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Extension.h 3 | // CYPasswordViewDemo 4 | // 5 | // Created by cheny on 15/10/8. 6 | // Copyright © 2015年 zhssit. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (Extension) 12 | 13 | // 在分类里面自动生成get,set方法 14 | @property (nonatomic, assign) CGFloat x; 15 | @property (nonatomic, assign) CGFloat y; 16 | @property (nonatomic, assign) CGFloat maxX; 17 | @property (nonatomic, assign) CGFloat maxY; 18 | @property (nonatomic, assign) CGFloat centerX; 19 | @property (nonatomic, assign) CGFloat centerY; 20 | @property (nonatomic, assign) CGFloat width; 21 | @property (nonatomic, assign) CGFloat height; 22 | @property (nonatomic, assign) CGSize size; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /CYPasswordView/UIView+Extension.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Extension.m 3 | // CYPasswordViewDemo 4 | // 5 | // Created by cheny on 15/10/8. 6 | // Copyright © 2015年 zhssit. All rights reserved. 7 | // 8 | 9 | #import "UIView+Extension.h" 10 | 11 | @implementation UIView (Extension) 12 | 13 | - (void)setX:(CGFloat)x 14 | { 15 | CGRect frame = self.frame; 16 | frame.origin.x = x; 17 | self.frame = frame; 18 | } 19 | 20 | - (CGFloat)x 21 | { 22 | return self.frame.origin.x; 23 | } 24 | 25 | - (void)setMaxX:(CGFloat)maxX 26 | { 27 | self.x = maxX - self.width; 28 | } 29 | 30 | - (CGFloat)maxX 31 | { 32 | return CGRectGetMaxX(self.frame); 33 | } 34 | 35 | - (void)setMaxY:(CGFloat)maxY 36 | { 37 | self.y = maxY - self.height; 38 | } 39 | 40 | - (CGFloat)maxY 41 | { 42 | return CGRectGetMaxY(self.frame); 43 | } 44 | 45 | - (void)setY:(CGFloat)y 46 | { 47 | CGRect frame = self.frame; 48 | frame.origin.y = y; 49 | self.frame = frame; 50 | } 51 | 52 | - (CGFloat)y 53 | { 54 | return self.frame.origin.y; 55 | } 56 | 57 | - (void)setCenterX:(CGFloat)centerX 58 | { 59 | CGPoint center = self.center; 60 | center.x = centerX; 61 | self.center = center; 62 | } 63 | 64 | - (CGFloat)centerX 65 | { 66 | return self.center.x; 67 | } 68 | 69 | - (void)setCenterY:(CGFloat)centerY 70 | { 71 | CGPoint center = self.center; 72 | center.y = centerY; 73 | self.center = center; 74 | } 75 | 76 | - (CGFloat)centerY 77 | { 78 | return self.center.y; 79 | } 80 | 81 | - (void)setWidth:(CGFloat)width 82 | { 83 | CGRect frame = self.frame; 84 | frame.size.width = width; 85 | self.frame = frame; 86 | } 87 | 88 | - (CGFloat)width 89 | { 90 | return self.frame.size.width; 91 | } 92 | 93 | - (void)setHeight:(CGFloat)height 94 | { 95 | CGRect frame = self.frame; 96 | frame.size.height = height; 97 | self.frame = frame; 98 | } 99 | 100 | - (CGFloat)height 101 | { 102 | return self.frame.size.height; 103 | } 104 | 105 | - (void)setSize:(CGSize)size 106 | { 107 | // self.width = size.width; 108 | // self.height = size.height; 109 | CGRect frame = self.frame; 110 | frame.size = size; 111 | self.frame = frame; 112 | } 113 | 114 | - (CGSize)size 115 | { 116 | return self.frame.size; 117 | } 118 | 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordViewDemo/.DS_Store -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 18A5355D1F62F6B800A23CE9 /* CYConst.m in Sources */ = {isa = PBXBuildFile; fileRef = 18A535531F62F6B800A23CE9 /* CYConst.m */; }; 11 | 18A5355E1F62F6B800A23CE9 /* CYPasswordInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 18A535551F62F6B800A23CE9 /* CYPasswordInputView.m */; }; 12 | 18A5355F1F62F6B800A23CE9 /* CYPasswordView.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 18A535561F62F6B800A23CE9 /* CYPasswordView.bundle */; }; 13 | 18A535601F62F6B800A23CE9 /* CYPasswordView.m in Sources */ = {isa = PBXBuildFile; fileRef = 18A535581F62F6B800A23CE9 /* CYPasswordView.m */; }; 14 | 18A535611F62F6B800A23CE9 /* NSBundle+CYPasswordView.m in Sources */ = {isa = PBXBuildFile; fileRef = 18A5355A1F62F6B800A23CE9 /* NSBundle+CYPasswordView.m */; }; 15 | 18A535621F62F6B800A23CE9 /* UIView+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 18A5355C1F62F6B800A23CE9 /* UIView+Extension.m */; }; 16 | 18C053A41BD205FE008889D3 /* MBProgressHUD+MJ.m in Sources */ = {isa = PBXBuildFile; fileRef = 18C053A01BD205FE008889D3 /* MBProgressHUD+MJ.m */; }; 17 | 18C053A51BD205FE008889D3 /* MBProgressHUD.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 18C053A11BD205FE008889D3 /* MBProgressHUD.bundle */; }; 18 | 18C053A61BD205FE008889D3 /* MBProgressHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 18C053A31BD205FE008889D3 /* MBProgressHUD.m */; }; 19 | 9AE0840E1BC6B61100BA6950 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AE0840D1BC6B61100BA6950 /* main.m */; }; 20 | 9AE084111BC6B61100BA6950 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AE084101BC6B61100BA6950 /* AppDelegate.m */; }; 21 | 9AE084141BC6B61100BA6950 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AE084131BC6B61100BA6950 /* ViewController.m */; }; 22 | 9AE084171BC6B61100BA6950 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9AE084151BC6B61100BA6950 /* Main.storyboard */; }; 23 | 9AE084191BC6B61100BA6950 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9AE084181BC6B61100BA6950 /* Assets.xcassets */; }; 24 | 9AE0841C1BC6B61100BA6950 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9AE0841A1BC6B61100BA6950 /* LaunchScreen.storyboard */; }; 25 | F72E80F72518B71E00BAAACE /* UIDevice+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = F72E80F62518B71E00BAAACE /* UIDevice+Extension.m */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 18A535521F62F6B800A23CE9 /* CYConst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYConst.h; sourceTree = ""; }; 30 | 18A535531F62F6B800A23CE9 /* CYConst.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYConst.m; sourceTree = ""; }; 31 | 18A535541F62F6B800A23CE9 /* CYPasswordInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYPasswordInputView.h; sourceTree = ""; }; 32 | 18A535551F62F6B800A23CE9 /* CYPasswordInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYPasswordInputView.m; sourceTree = ""; }; 33 | 18A535561F62F6B800A23CE9 /* CYPasswordView.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = CYPasswordView.bundle; sourceTree = ""; }; 34 | 18A535571F62F6B800A23CE9 /* CYPasswordView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYPasswordView.h; sourceTree = ""; }; 35 | 18A535581F62F6B800A23CE9 /* CYPasswordView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYPasswordView.m; sourceTree = ""; }; 36 | 18A535591F62F6B800A23CE9 /* NSBundle+CYPasswordView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+CYPasswordView.h"; sourceTree = ""; }; 37 | 18A5355A1F62F6B800A23CE9 /* NSBundle+CYPasswordView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+CYPasswordView.m"; sourceTree = ""; }; 38 | 18A5355B1F62F6B800A23CE9 /* UIView+Extension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Extension.h"; sourceTree = ""; }; 39 | 18A5355C1F62F6B800A23CE9 /* UIView+Extension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Extension.m"; sourceTree = ""; }; 40 | 18C0539F1BD205FE008889D3 /* MBProgressHUD+MJ.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MBProgressHUD+MJ.h"; sourceTree = ""; }; 41 | 18C053A01BD205FE008889D3 /* MBProgressHUD+MJ.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MBProgressHUD+MJ.m"; sourceTree = ""; }; 42 | 18C053A11BD205FE008889D3 /* MBProgressHUD.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = MBProgressHUD.bundle; sourceTree = ""; }; 43 | 18C053A21BD205FE008889D3 /* MBProgressHUD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBProgressHUD.h; sourceTree = ""; }; 44 | 18C053A31BD205FE008889D3 /* MBProgressHUD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBProgressHUD.m; sourceTree = ""; }; 45 | 9AE084091BC6B61100BA6950 /* CYPasswordViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CYPasswordViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 9AE0840D1BC6B61100BA6950 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 47 | 9AE0840F1BC6B61100BA6950 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 48 | 9AE084101BC6B61100BA6950 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 49 | 9AE084121BC6B61100BA6950 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 50 | 9AE084131BC6B61100BA6950 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 51 | 9AE084161BC6B61100BA6950 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 52 | 9AE084181BC6B61100BA6950 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 53 | 9AE0841B1BC6B61100BA6950 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 54 | 9AE0841D1BC6B61100BA6950 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | F72E80F52518B6E000BAAACE /* UIDevice+Extension.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIDevice+Extension.h"; sourceTree = ""; }; 56 | F72E80F62518B71E00BAAACE /* UIDevice+Extension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+Extension.m"; sourceTree = ""; }; 57 | /* End PBXFileReference section */ 58 | 59 | /* Begin PBXFrameworksBuildPhase section */ 60 | 9AE084061BC6B61100BA6950 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXFrameworksBuildPhase section */ 68 | 69 | /* Begin PBXGroup section */ 70 | 18A535511F62F6B800A23CE9 /* CYPasswordView */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 18A535521F62F6B800A23CE9 /* CYConst.h */, 74 | 18A535531F62F6B800A23CE9 /* CYConst.m */, 75 | 18A535541F62F6B800A23CE9 /* CYPasswordInputView.h */, 76 | 18A535551F62F6B800A23CE9 /* CYPasswordInputView.m */, 77 | 18A535561F62F6B800A23CE9 /* CYPasswordView.bundle */, 78 | 18A535571F62F6B800A23CE9 /* CYPasswordView.h */, 79 | 18A535581F62F6B800A23CE9 /* CYPasswordView.m */, 80 | 18A535591F62F6B800A23CE9 /* NSBundle+CYPasswordView.h */, 81 | 18A5355A1F62F6B800A23CE9 /* NSBundle+CYPasswordView.m */, 82 | 18A5355B1F62F6B800A23CE9 /* UIView+Extension.h */, 83 | 18A5355C1F62F6B800A23CE9 /* UIView+Extension.m */, 84 | F72E80F52518B6E000BAAACE /* UIDevice+Extension.h */, 85 | F72E80F62518B71E00BAAACE /* UIDevice+Extension.m */, 86 | ); 87 | name = CYPasswordView; 88 | path = ../../CYPasswordView; 89 | sourceTree = ""; 90 | }; 91 | 18C0539E1BD205FE008889D3 /* MBProgressHUD */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 18C0539F1BD205FE008889D3 /* MBProgressHUD+MJ.h */, 95 | 18C053A01BD205FE008889D3 /* MBProgressHUD+MJ.m */, 96 | 18C053A11BD205FE008889D3 /* MBProgressHUD.bundle */, 97 | 18C053A21BD205FE008889D3 /* MBProgressHUD.h */, 98 | 18C053A31BD205FE008889D3 /* MBProgressHUD.m */, 99 | ); 100 | path = MBProgressHUD; 101 | sourceTree = ""; 102 | }; 103 | 9AE084001BC6B61100BA6950 = { 104 | isa = PBXGroup; 105 | children = ( 106 | 9AE0840B1BC6B61100BA6950 /* CYPasswordViewDemo */, 107 | 9AE0840A1BC6B61100BA6950 /* Products */, 108 | ); 109 | sourceTree = ""; 110 | }; 111 | 9AE0840A1BC6B61100BA6950 /* Products */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 9AE084091BC6B61100BA6950 /* CYPasswordViewDemo.app */, 115 | ); 116 | name = Products; 117 | sourceTree = ""; 118 | }; 119 | 9AE0840B1BC6B61100BA6950 /* CYPasswordViewDemo */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 18A535511F62F6B800A23CE9 /* CYPasswordView */, 123 | 9AE0840F1BC6B61100BA6950 /* AppDelegate.h */, 124 | 9AE084101BC6B61100BA6950 /* AppDelegate.m */, 125 | 9AE084121BC6B61100BA6950 /* ViewController.h */, 126 | 9AE084131BC6B61100BA6950 /* ViewController.m */, 127 | 9AE084151BC6B61100BA6950 /* Main.storyboard */, 128 | 18C0539E1BD205FE008889D3 /* MBProgressHUD */, 129 | 9AE084181BC6B61100BA6950 /* Assets.xcassets */, 130 | 9AE0841A1BC6B61100BA6950 /* LaunchScreen.storyboard */, 131 | 9AE0841D1BC6B61100BA6950 /* Info.plist */, 132 | 9AE0840C1BC6B61100BA6950 /* Supporting Files */, 133 | ); 134 | path = CYPasswordViewDemo; 135 | sourceTree = ""; 136 | }; 137 | 9AE0840C1BC6B61100BA6950 /* Supporting Files */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 9AE0840D1BC6B61100BA6950 /* main.m */, 141 | ); 142 | name = "Supporting Files"; 143 | sourceTree = ""; 144 | }; 145 | /* End PBXGroup section */ 146 | 147 | /* Begin PBXNativeTarget section */ 148 | 9AE084081BC6B61100BA6950 /* CYPasswordViewDemo */ = { 149 | isa = PBXNativeTarget; 150 | buildConfigurationList = 9AE084201BC6B61100BA6950 /* Build configuration list for PBXNativeTarget "CYPasswordViewDemo" */; 151 | buildPhases = ( 152 | 9AE084051BC6B61100BA6950 /* Sources */, 153 | 9AE084061BC6B61100BA6950 /* Frameworks */, 154 | 9AE084071BC6B61100BA6950 /* Resources */, 155 | ); 156 | buildRules = ( 157 | ); 158 | dependencies = ( 159 | ); 160 | name = CYPasswordViewDemo; 161 | productName = CYPasswordViewDemo; 162 | productReference = 9AE084091BC6B61100BA6950 /* CYPasswordViewDemo.app */; 163 | productType = "com.apple.product-type.application"; 164 | }; 165 | /* End PBXNativeTarget section */ 166 | 167 | /* Begin PBXProject section */ 168 | 9AE084011BC6B61100BA6950 /* Project object */ = { 169 | isa = PBXProject; 170 | attributes = { 171 | CLASSPREFIX = CY; 172 | LastUpgradeCheck = 0700; 173 | ORGANIZATIONNAME = zhssit; 174 | TargetAttributes = { 175 | 9AE084081BC6B61100BA6950 = { 176 | CreatedOnToolsVersion = 7.0; 177 | }; 178 | }; 179 | }; 180 | buildConfigurationList = 9AE084041BC6B61100BA6950 /* Build configuration list for PBXProject "CYPasswordViewDemo" */; 181 | compatibilityVersion = "Xcode 3.2"; 182 | developmentRegion = English; 183 | hasScannedForEncodings = 0; 184 | knownRegions = ( 185 | English, 186 | en, 187 | Base, 188 | ); 189 | mainGroup = 9AE084001BC6B61100BA6950; 190 | productRefGroup = 9AE0840A1BC6B61100BA6950 /* Products */; 191 | projectDirPath = ""; 192 | projectRoot = ""; 193 | targets = ( 194 | 9AE084081BC6B61100BA6950 /* CYPasswordViewDemo */, 195 | ); 196 | }; 197 | /* End PBXProject section */ 198 | 199 | /* Begin PBXResourcesBuildPhase section */ 200 | 9AE084071BC6B61100BA6950 /* Resources */ = { 201 | isa = PBXResourcesBuildPhase; 202 | buildActionMask = 2147483647; 203 | files = ( 204 | 9AE0841C1BC6B61100BA6950 /* LaunchScreen.storyboard in Resources */, 205 | 9AE084191BC6B61100BA6950 /* Assets.xcassets in Resources */, 206 | 18C053A51BD205FE008889D3 /* MBProgressHUD.bundle in Resources */, 207 | 9AE084171BC6B61100BA6950 /* Main.storyboard in Resources */, 208 | 18A5355F1F62F6B800A23CE9 /* CYPasswordView.bundle in Resources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXResourcesBuildPhase section */ 213 | 214 | /* Begin PBXSourcesBuildPhase section */ 215 | 9AE084051BC6B61100BA6950 /* Sources */ = { 216 | isa = PBXSourcesBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | 18A535621F62F6B800A23CE9 /* UIView+Extension.m in Sources */, 220 | 18A5355E1F62F6B800A23CE9 /* CYPasswordInputView.m in Sources */, 221 | 9AE084141BC6B61100BA6950 /* ViewController.m in Sources */, 222 | 18C053A61BD205FE008889D3 /* MBProgressHUD.m in Sources */, 223 | 18C053A41BD205FE008889D3 /* MBProgressHUD+MJ.m in Sources */, 224 | 9AE084111BC6B61100BA6950 /* AppDelegate.m in Sources */, 225 | 18A535611F62F6B800A23CE9 /* NSBundle+CYPasswordView.m in Sources */, 226 | F72E80F72518B71E00BAAACE /* UIDevice+Extension.m in Sources */, 227 | 18A535601F62F6B800A23CE9 /* CYPasswordView.m in Sources */, 228 | 9AE0840E1BC6B61100BA6950 /* main.m in Sources */, 229 | 18A5355D1F62F6B800A23CE9 /* CYConst.m in Sources */, 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | }; 233 | /* End PBXSourcesBuildPhase section */ 234 | 235 | /* Begin PBXVariantGroup section */ 236 | 9AE084151BC6B61100BA6950 /* Main.storyboard */ = { 237 | isa = PBXVariantGroup; 238 | children = ( 239 | 9AE084161BC6B61100BA6950 /* Base */, 240 | ); 241 | name = Main.storyboard; 242 | sourceTree = ""; 243 | }; 244 | 9AE0841A1BC6B61100BA6950 /* LaunchScreen.storyboard */ = { 245 | isa = PBXVariantGroup; 246 | children = ( 247 | 9AE0841B1BC6B61100BA6950 /* Base */, 248 | ); 249 | name = LaunchScreen.storyboard; 250 | sourceTree = ""; 251 | }; 252 | /* End PBXVariantGroup section */ 253 | 254 | /* Begin XCBuildConfiguration section */ 255 | 9AE0841E1BC6B61100BA6950 /* Debug */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | ALWAYS_SEARCH_USER_PATHS = NO; 259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 260 | CLANG_CXX_LIBRARY = "libc++"; 261 | CLANG_ENABLE_MODULES = YES; 262 | CLANG_ENABLE_OBJC_ARC = YES; 263 | CLANG_WARN_BOOL_CONVERSION = YES; 264 | CLANG_WARN_CONSTANT_CONVERSION = YES; 265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 266 | CLANG_WARN_EMPTY_BODY = YES; 267 | CLANG_WARN_ENUM_CONVERSION = YES; 268 | CLANG_WARN_INT_CONVERSION = YES; 269 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 270 | CLANG_WARN_UNREACHABLE_CODE = YES; 271 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 272 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 273 | COPY_PHASE_STRIP = NO; 274 | DEBUG_INFORMATION_FORMAT = dwarf; 275 | ENABLE_STRICT_OBJC_MSGSEND = YES; 276 | ENABLE_TESTABILITY = YES; 277 | GCC_C_LANGUAGE_STANDARD = gnu99; 278 | GCC_DYNAMIC_NO_PIC = NO; 279 | GCC_NO_COMMON_BLOCKS = YES; 280 | GCC_OPTIMIZATION_LEVEL = 0; 281 | GCC_PREPROCESSOR_DEFINITIONS = ( 282 | "DEBUG=1", 283 | "$(inherited)", 284 | ); 285 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 286 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 287 | GCC_WARN_UNDECLARED_SELECTOR = YES; 288 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 289 | GCC_WARN_UNUSED_FUNCTION = YES; 290 | GCC_WARN_UNUSED_VARIABLE = YES; 291 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 292 | MTL_ENABLE_DEBUG_INFO = YES; 293 | ONLY_ACTIVE_ARCH = YES; 294 | SDKROOT = iphoneos; 295 | }; 296 | name = Debug; 297 | }; 298 | 9AE0841F1BC6B61100BA6950 /* Release */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | ALWAYS_SEARCH_USER_PATHS = NO; 302 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 303 | CLANG_CXX_LIBRARY = "libc++"; 304 | CLANG_ENABLE_MODULES = YES; 305 | CLANG_ENABLE_OBJC_ARC = YES; 306 | CLANG_WARN_BOOL_CONVERSION = YES; 307 | CLANG_WARN_CONSTANT_CONVERSION = YES; 308 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 309 | CLANG_WARN_EMPTY_BODY = YES; 310 | CLANG_WARN_ENUM_CONVERSION = YES; 311 | CLANG_WARN_INT_CONVERSION = YES; 312 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 313 | CLANG_WARN_UNREACHABLE_CODE = YES; 314 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 315 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 316 | COPY_PHASE_STRIP = NO; 317 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 318 | ENABLE_NS_ASSERTIONS = NO; 319 | ENABLE_STRICT_OBJC_MSGSEND = YES; 320 | GCC_C_LANGUAGE_STANDARD = gnu99; 321 | GCC_NO_COMMON_BLOCKS = YES; 322 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 323 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 324 | GCC_WARN_UNDECLARED_SELECTOR = YES; 325 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 326 | GCC_WARN_UNUSED_FUNCTION = YES; 327 | GCC_WARN_UNUSED_VARIABLE = YES; 328 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 329 | MTL_ENABLE_DEBUG_INFO = NO; 330 | SDKROOT = iphoneos; 331 | VALIDATE_PRODUCT = YES; 332 | }; 333 | name = Release; 334 | }; 335 | 9AE084211BC6B61100BA6950 /* Debug */ = { 336 | isa = XCBuildConfiguration; 337 | buildSettings = { 338 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 339 | INFOPLIST_FILE = CYPasswordViewDemo/Info.plist; 340 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 341 | PRODUCT_BUNDLE_IDENTIFIER = com.develop.CYPasswordViewDemo; 342 | PRODUCT_NAME = "$(TARGET_NAME)"; 343 | }; 344 | name = Debug; 345 | }; 346 | 9AE084221BC6B61100BA6950 /* Release */ = { 347 | isa = XCBuildConfiguration; 348 | buildSettings = { 349 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 350 | INFOPLIST_FILE = CYPasswordViewDemo/Info.plist; 351 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 352 | PRODUCT_BUNDLE_IDENTIFIER = com.develop.CYPasswordViewDemo; 353 | PRODUCT_NAME = "$(TARGET_NAME)"; 354 | }; 355 | name = Release; 356 | }; 357 | /* End XCBuildConfiguration section */ 358 | 359 | /* Begin XCConfigurationList section */ 360 | 9AE084041BC6B61100BA6950 /* Build configuration list for PBXProject "CYPasswordViewDemo" */ = { 361 | isa = XCConfigurationList; 362 | buildConfigurations = ( 363 | 9AE0841E1BC6B61100BA6950 /* Debug */, 364 | 9AE0841F1BC6B61100BA6950 /* Release */, 365 | ); 366 | defaultConfigurationIsVisible = 0; 367 | defaultConfigurationName = Release; 368 | }; 369 | 9AE084201BC6B61100BA6950 /* Build configuration list for PBXNativeTarget "CYPasswordViewDemo" */ = { 370 | isa = XCConfigurationList; 371 | buildConfigurations = ( 372 | 9AE084211BC6B61100BA6950 /* Debug */, 373 | 9AE084221BC6B61100BA6950 /* Release */, 374 | ); 375 | defaultConfigurationIsVisible = 0; 376 | defaultConfigurationName = Release; 377 | }; 378 | /* End XCConfigurationList section */ 379 | }; 380 | rootObject = 9AE084011BC6B61100BA6950 /* Project object */; 381 | } 382 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordViewDemo/CYPasswordViewDemo/.DS_Store -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // CYPasswordViewDemo 4 | // 5 | // Created by cheny on 15/10/8. 6 | // Copyright © 2015年 zhssit. 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 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // CYPasswordViewDemo 4 | // 5 | // Created by cheny on 15/10/8. 6 | // Copyright © 2015年 zhssit. 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 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/Assets.xcassets/arrow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "account_next@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/Assets.xcassets/arrow.imageset/account_next@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordViewDemo/CYPasswordViewDemo/Assets.xcassets/arrow.imageset/account_next@2x.png -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/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 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 75 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 112 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 141 | 148 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/CYPasswordViewDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordViewDemo/CYPasswordViewDemo/CYPasswordViewDemo.gif -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD+MJ.h: -------------------------------------------------------------------------------- 1 | // 2 | // MBProgressHUD+MJ.h 3 | // 4 | // Created by MJ Lee on 13/4/18. 5 | // Copyright (c) 2015年 itcast. All rights reserved. 6 | // 7 | 8 | 9 | #import "MBProgressHUD.h" 10 | 11 | @interface MBProgressHUD (MJ) 12 | + (void)showSuccess:(NSString *)success toView:(UIView *)view; 13 | + (void)showError:(NSString *)error toView:(UIView *)view; 14 | 15 | + (MBProgressHUD *)showMessage:(NSString *)message toView:(UIView *)view; 16 | 17 | 18 | + (void)showSuccess:(NSString *)success; 19 | + (void)showError:(NSString *)error; 20 | 21 | + (MBProgressHUD *)showMessage:(NSString *)message; 22 | 23 | + (void)hideHUDForView:(UIView *)view; 24 | + (void)hideHUD; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD+MJ.m: -------------------------------------------------------------------------------- 1 | // 2 | // MBProgressHUD+MJ.m 3 | // 4 | // Created by MJ Lee on 13/4/18. 5 | // Copyright (c) 2015年 itcast. All rights reserved. 6 | // 7 | 8 | #import "MBProgressHUD+MJ.h" 9 | 10 | @implementation MBProgressHUD (MJ) 11 | #pragma mark 显示信息 12 | + (void)show:(NSString *)text icon:(NSString *)icon view:(UIView *)view 13 | { 14 | // if (view == nil) view = [[UIApplication sharedApplication].windows lastObject]; 15 | //在StatusBarHud 显示期间,由于lastObject的Frame的缘故将导致 16 | if (view == nil) view = [[UIApplication sharedApplication] keyWindow]; 17 | // 快速显示一个提示信息 18 | MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:view animated:YES]; 19 | hud.labelText = text; 20 | // 设置图片 21 | hud.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"MBProgressHUD.bundle/%@", icon]]]; 22 | // 再设置模式 23 | hud.mode = MBProgressHUDModeCustomView; 24 | 25 | // 隐藏时候从父控件中移除 26 | hud.removeFromSuperViewOnHide = YES; 27 | 28 | // 1秒之后再消失 29 | [hud hide:YES afterDelay:0.7]; 30 | } 31 | 32 | #pragma mark 显示错误信息 33 | + (void)showError:(NSString *)error toView:(UIView *)view{ 34 | [self show:error icon:@"error.png" view:view]; 35 | } 36 | 37 | + (void)showSuccess:(NSString *)success toView:(UIView *)view 38 | { 39 | [self show:success icon:@"success.png" view:view]; 40 | } 41 | 42 | #pragma mark 显示一些信息 43 | + (MBProgressHUD *)showMessage:(NSString *)message toView:(UIView *)view { 44 | // if (view == nil) view = [[UIApplication sharedApplication].windows lastObject]; 45 | //在StatusBarHud 显示期间,由于lastObject的Frame的缘故将导致 46 | if (view == nil) view = [[UIApplication sharedApplication] keyWindow]; 47 | 48 | // 快速显示一个提示信息 49 | MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:view animated:YES]; 50 | hud.labelText = message; 51 | // 隐藏时候从父控件中移除 52 | hud.removeFromSuperViewOnHide = YES; 53 | // YES代表需要蒙版效果 54 | hud.dimBackground = YES; 55 | return hud; 56 | } 57 | 58 | + (void)showSuccess:(NSString *)success 59 | { 60 | [self showSuccess:success toView:nil]; 61 | } 62 | 63 | + (void)showError:(NSString *)error 64 | { 65 | [self showError:error toView:nil]; 66 | } 67 | 68 | + (MBProgressHUD *)showMessage:(NSString *)message 69 | { 70 | return [self showMessage:message toView:nil]; 71 | } 72 | 73 | + (void)hideHUDForView:(UIView *)view 74 | { 75 | // if (view == nil) view = [[UIApplication sharedApplication].windows lastObject]; 76 | //在StatusBarHud 显示期间,由于lastObject的Frame的缘故将导致 77 | if (view == nil) view = [[UIApplication sharedApplication] keyWindow]; 78 | [self hideHUDForView:view animated:YES]; 79 | } 80 | 81 | + (void)hideHUD 82 | { 83 | [self hideHUDForView:nil]; 84 | } 85 | @end 86 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD.bundle/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD.bundle/error.png -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD.bundle/error@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD.bundle/error@2x.png -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD.bundle/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD.bundle/success.png -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD.bundle/success@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chernyog/CYPasswordView/b2df67cc54ca6cc09646a46dfca480db89519467/CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD.bundle/success@2x.png -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD.h: -------------------------------------------------------------------------------- 1 | // 2 | // MBProgressHUD.h 3 | // Version 0.9 4 | // Created by Matej Bukovinski on 2.4.09. 5 | // 6 | 7 | // This code is distributed under the terms and conditions of the MIT license. 8 | 9 | // Copyright (c) 2013 Matej Bukovinski 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | 29 | #import 30 | #import 31 | #import 32 | 33 | @protocol MBProgressHUDDelegate; 34 | 35 | 36 | typedef enum { 37 | /** Progress is shown using an UIActivityIndicatorView. This is the default. */ 38 | MBProgressHUDModeIndeterminate, 39 | /** Progress is shown using a round, pie-chart like, progress view. */ 40 | MBProgressHUDModeDeterminate, 41 | /** Progress is shown using a horizontal progress bar */ 42 | MBProgressHUDModeDeterminateHorizontalBar, 43 | /** Progress is shown using a ring-shaped progress view. */ 44 | MBProgressHUDModeAnnularDeterminate, 45 | /** Shows a custom view */ 46 | MBProgressHUDModeCustomView, 47 | /** Shows only labels */ 48 | MBProgressHUDModeText 49 | } MBProgressHUDMode; 50 | 51 | typedef enum { 52 | /** Opacity animation */ 53 | MBProgressHUDAnimationFade, 54 | /** Opacity + scale animation */ 55 | MBProgressHUDAnimationZoom, 56 | MBProgressHUDAnimationZoomOut = MBProgressHUDAnimationZoom, 57 | MBProgressHUDAnimationZoomIn 58 | } MBProgressHUDAnimation; 59 | 60 | 61 | #ifndef MB_INSTANCETYPE 62 | #if __has_feature(objc_instancetype) 63 | #define MB_INSTANCETYPE instancetype 64 | #else 65 | #define MB_INSTANCETYPE id 66 | #endif 67 | #endif 68 | 69 | #ifndef MB_STRONG 70 | #if __has_feature(objc_arc) 71 | #define MB_STRONG strong 72 | #else 73 | #define MB_STRONG retain 74 | #endif 75 | #endif 76 | 77 | #ifndef MB_WEAK 78 | #if __has_feature(objc_arc_weak) 79 | #define MB_WEAK weak 80 | #elif __has_feature(objc_arc) 81 | #define MB_WEAK unsafe_unretained 82 | #else 83 | #define MB_WEAK assign 84 | #endif 85 | #endif 86 | 87 | #if NS_BLOCKS_AVAILABLE 88 | typedef void (^MBProgressHUDCompletionBlock)(); 89 | #endif 90 | 91 | 92 | /** 93 | * Displays a simple HUD window containing a progress indicator and two optional labels for short messages. 94 | * 95 | * This is a simple drop-in class for displaying a progress HUD view similar to Apple's private UIProgressHUD class. 96 | * The MBProgressHUD window spans over the entire space given to it by the initWithFrame constructor and catches all 97 | * user input on this region, thereby preventing the user operations on components below the view. The HUD itself is 98 | * drawn centered as a rounded semi-transparent view which resizes depending on the user specified content. 99 | * 100 | * This view supports four modes of operation: 101 | * - MBProgressHUDModeIndeterminate - shows a UIActivityIndicatorView 102 | * - MBProgressHUDModeDeterminate - shows a custom round progress indicator 103 | * - MBProgressHUDModeAnnularDeterminate - shows a custom annular progress indicator 104 | * - MBProgressHUDModeCustomView - shows an arbitrary, user specified view (@see customView) 105 | * 106 | * All three modes can have optional labels assigned: 107 | * - If the labelText property is set and non-empty then a label containing the provided content is placed below the 108 | * indicator view. 109 | * - If also the detailsLabelText property is set then another label is placed below the first label. 110 | */ 111 | @interface MBProgressHUD : UIView 112 | 113 | /** 114 | * Creates a new HUD, adds it to provided view and shows it. The counterpart to this method is hideHUDForView:animated:. 115 | * 116 | * @param view The view that the HUD will be added to 117 | * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use 118 | * animations while appearing. 119 | * @return A reference to the created HUD. 120 | * 121 | * @see hideHUDForView:animated: 122 | * @see animationType 123 | */ 124 | + (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated; 125 | 126 | /** 127 | * Finds the top-most HUD subview and hides it. The counterpart to this method is showHUDAddedTo:animated:. 128 | * 129 | * @param view The view that is going to be searched for a HUD subview. 130 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 131 | * animations while disappearing. 132 | * @return YES if a HUD was found and removed, NO otherwise. 133 | * 134 | * @see showHUDAddedTo:animated: 135 | * @see animationType 136 | */ 137 | + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated; 138 | 139 | /** 140 | * Finds all the HUD subviews and hides them. 141 | * 142 | * @param view The view that is going to be searched for HUD subviews. 143 | * @param animated If set to YES the HUDs will disappear using the current animationType. If set to NO the HUDs will not use 144 | * animations while disappearing. 145 | * @return the number of HUDs found and removed. 146 | * 147 | * @see hideHUDForView:animated: 148 | * @see animationType 149 | */ 150 | + (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated; 151 | 152 | /** 153 | * Finds the top-most HUD subview and returns it. 154 | * 155 | * @param view The view that is going to be searched. 156 | * @return A reference to the last HUD subview discovered. 157 | */ 158 | + (MB_INSTANCETYPE)HUDForView:(UIView *)view; 159 | 160 | /** 161 | * Finds all HUD subviews and returns them. 162 | * 163 | * @param view The view that is going to be searched. 164 | * @return All found HUD views (array of MBProgressHUD objects). 165 | */ 166 | + (NSArray *)allHUDsForView:(UIView *)view; 167 | 168 | /** 169 | * A convenience constructor that initializes the HUD with the window's bounds. Calls the designated constructor with 170 | * window.bounds as the parameter. 171 | * 172 | * @param window The window instance that will provide the bounds for the HUD. Should be the same instance as 173 | * the HUD's superview (i.e., the window that the HUD will be added to). 174 | */ 175 | - (id)initWithWindow:(UIWindow *)window; 176 | 177 | /** 178 | * A convenience constructor that initializes the HUD with the view's bounds. Calls the designated constructor with 179 | * view.bounds as the parameter 180 | * 181 | * @param view The view instance that will provide the bounds for the HUD. Should be the same instance as 182 | * the HUD's superview (i.e., the view that the HUD will be added to). 183 | */ 184 | - (id)initWithView:(UIView *)view; 185 | 186 | /** 187 | * Display the HUD. You need to make sure that the main thread completes its run loop soon after this method call so 188 | * the user interface can be updated. Call this method when your task is already set-up to be executed in a new thread 189 | * (e.g., when using something like NSOperation or calling an asynchronous call like NSURLRequest). 190 | * 191 | * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use 192 | * animations while appearing. 193 | * 194 | * @see animationType 195 | */ 196 | - (void)show:(BOOL)animated; 197 | 198 | /** 199 | * Hide the HUD. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to 200 | * hide the HUD when your task completes. 201 | * 202 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 203 | * animations while disappearing. 204 | * 205 | * @see animationType 206 | */ 207 | - (void)hide:(BOOL)animated; 208 | 209 | /** 210 | * Hide the HUD after a delay. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to 211 | * hide the HUD when your task completes. 212 | * 213 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 214 | * animations while disappearing. 215 | * @param delay Delay in seconds until the HUD is hidden. 216 | * 217 | * @see animationType 218 | */ 219 | - (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay; 220 | 221 | /** 222 | * Shows the HUD while a background task is executing in a new thread, then hides the HUD. 223 | * 224 | * This method also takes care of autorelease pools so your method does not have to be concerned with setting up a 225 | * pool. 226 | * 227 | * @param method The method to be executed while the HUD is shown. This method will be executed in a new thread. 228 | * @param target The object that the target method belongs to. 229 | * @param object An optional object to be passed to the method. 230 | * @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will not use 231 | * animations while (dis)appearing. 232 | */ 233 | - (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated; 234 | 235 | #if NS_BLOCKS_AVAILABLE 236 | 237 | /** 238 | * Shows the HUD while a block is executing on a background queue, then hides the HUD. 239 | * 240 | * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: 241 | */ 242 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block; 243 | 244 | /** 245 | * Shows the HUD while a block is executing on a background queue, then hides the HUD. 246 | * 247 | * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: 248 | */ 249 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(MBProgressHUDCompletionBlock)completion; 250 | 251 | /** 252 | * Shows the HUD while a block is executing on the specified dispatch queue, then hides the HUD. 253 | * 254 | * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: 255 | */ 256 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue; 257 | 258 | /** 259 | * Shows the HUD while a block is executing on the specified dispatch queue, executes completion block on the main queue, and then hides the HUD. 260 | * 261 | * @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will 262 | * not use animations while (dis)appearing. 263 | * @param block The block to be executed while the HUD is shown. 264 | * @param queue The dispatch queue on which the block should be executed. 265 | * @param completion The block to be executed on completion. 266 | * 267 | * @see completionBlock 268 | */ 269 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue 270 | completionBlock:(MBProgressHUDCompletionBlock)completion; 271 | 272 | /** 273 | * A block that gets called after the HUD was completely hidden. 274 | */ 275 | @property (copy) MBProgressHUDCompletionBlock completionBlock; 276 | 277 | #endif 278 | 279 | /** 280 | * MBProgressHUD operation mode. The default is MBProgressHUDModeIndeterminate. 281 | * 282 | * @see MBProgressHUDMode 283 | */ 284 | @property (assign) MBProgressHUDMode mode; 285 | 286 | /** 287 | * The animation type that should be used when the HUD is shown and hidden. 288 | * 289 | * @see MBProgressHUDAnimation 290 | */ 291 | @property (assign) MBProgressHUDAnimation animationType; 292 | 293 | /** 294 | * The UIView (e.g., a UIImageView) to be shown when the HUD is in MBProgressHUDModeCustomView. 295 | * For best results use a 37 by 37 pixel view (so the bounds match the built in indicator bounds). 296 | */ 297 | @property (MB_STRONG) UIView *customView; 298 | 299 | /** 300 | * The HUD delegate object. 301 | * 302 | * @see MBProgressHUDDelegate 303 | */ 304 | @property (MB_WEAK) id delegate; 305 | 306 | /** 307 | * An optional short message to be displayed below the activity indicator. The HUD is automatically resized to fit 308 | * the entire text. If the text is too long it will get clipped by displaying "..." at the end. If left unchanged or 309 | * set to @"", then no message is displayed. 310 | */ 311 | @property (copy) NSString *labelText; 312 | 313 | /** 314 | * An optional details message displayed below the labelText message. This message is displayed only if the labelText 315 | * property is also set and is different from an empty string (@""). The details text can span multiple lines. 316 | */ 317 | @property (copy) NSString *detailsLabelText; 318 | 319 | /** 320 | * The opacity of the HUD window. Defaults to 0.8 (80% opacity). 321 | */ 322 | @property (assign) float opacity; 323 | 324 | /** 325 | * The color of the HUD window. Defaults to black. If this property is set, color is set using 326 | * this UIColor and the opacity property is not used. using retain because performing copy on 327 | * UIColor base colors (like [UIColor greenColor]) cause problems with the copyZone. 328 | */ 329 | @property (MB_STRONG) UIColor *color; 330 | 331 | /** 332 | * The x-axis offset of the HUD relative to the centre of the superview. 333 | */ 334 | @property (assign) float xOffset; 335 | 336 | /** 337 | * The y-axis offset of the HUD relative to the centre of the superview. 338 | */ 339 | @property (assign) float yOffset; 340 | 341 | /** 342 | * The amount of space between the HUD edge and the HUD elements (labels, indicators or custom views). 343 | * Defaults to 20.0 344 | */ 345 | @property (assign) float margin; 346 | 347 | /** 348 | * The corner radius for the HUD 349 | * Defaults to 10.0 350 | */ 351 | @property (assign) float cornerRadius; 352 | 353 | /** 354 | * Cover the HUD background view with a radial gradient. 355 | */ 356 | @property (assign) BOOL dimBackground; 357 | 358 | /* 359 | * Grace period is the time (in seconds) that the invoked method may be run without 360 | * showing the HUD. If the task finishes before the grace time runs out, the HUD will 361 | * not be shown at all. 362 | * This may be used to prevent HUD display for very short tasks. 363 | * Defaults to 0 (no grace time). 364 | * Grace time functionality is only supported when the task status is known! 365 | * @see taskInProgress 366 | */ 367 | @property (assign) float graceTime; 368 | 369 | /** 370 | * The minimum time (in seconds) that the HUD is shown. 371 | * This avoids the problem of the HUD being shown and than instantly hidden. 372 | * Defaults to 0 (no minimum show time). 373 | */ 374 | @property (assign) float minShowTime; 375 | 376 | /** 377 | * Indicates that the executed operation is in progress. Needed for correct graceTime operation. 378 | * If you don't set a graceTime (different than 0.0) this does nothing. 379 | * This property is automatically set when using showWhileExecuting:onTarget:withObject:animated:. 380 | * When threading is done outside of the HUD (i.e., when the show: and hide: methods are used directly), 381 | * you need to set this property when your task starts and completes in order to have normal graceTime 382 | * functionality. 383 | */ 384 | @property (assign) BOOL taskInProgress; 385 | 386 | /** 387 | * Removes the HUD from its parent view when hidden. 388 | * Defaults to NO. 389 | */ 390 | @property (assign) BOOL removeFromSuperViewOnHide; 391 | 392 | /** 393 | * Font to be used for the main label. Set this property if the default is not adequate. 394 | */ 395 | @property (MB_STRONG) UIFont* labelFont; 396 | 397 | /** 398 | * Color to be used for the main label. Set this property if the default is not adequate. 399 | */ 400 | @property (MB_STRONG) UIColor* labelColor; 401 | 402 | /** 403 | * Font to be used for the details label. Set this property if the default is not adequate. 404 | */ 405 | @property (MB_STRONG) UIFont* detailsLabelFont; 406 | 407 | /** 408 | * Color to be used for the details label. Set this property if the default is not adequate. 409 | */ 410 | @property (MB_STRONG) UIColor* detailsLabelColor; 411 | 412 | /** 413 | * The color of the activity indicator. Defaults to [UIColor whiteColor] 414 | * Does nothing on pre iOS 5. 415 | */ 416 | @property (MB_STRONG) UIColor *activityIndicatorColor; 417 | 418 | /** 419 | * The progress of the progress indicator, from 0.0 to 1.0. Defaults to 0.0. 420 | */ 421 | @property (assign) float progress; 422 | 423 | /** 424 | * The minimum size of the HUD bezel. Defaults to CGSizeZero (no minimum size). 425 | */ 426 | @property (assign) CGSize minSize; 427 | 428 | 429 | /** 430 | * The actual size of the HUD bezel. 431 | * You can use this to limit touch handling on the bezel aria only. 432 | * @see https://github.com/jdg/MBProgressHUD/pull/200 433 | */ 434 | @property (atomic, assign, readonly) CGSize size; 435 | 436 | 437 | /** 438 | * Force the HUD dimensions to be equal if possible. 439 | */ 440 | @property (assign, getter = isSquare) BOOL square; 441 | 442 | @end 443 | 444 | 445 | @protocol MBProgressHUDDelegate 446 | 447 | @optional 448 | 449 | /** 450 | * Called after the HUD was fully hidden from the screen. 451 | */ 452 | - (void)hudWasHidden:(MBProgressHUD *)hud; 453 | 454 | @end 455 | 456 | 457 | /** 458 | * A progress view for showing definite progress by filling up a circle (pie chart). 459 | */ 460 | @interface MBRoundProgressView : UIView 461 | 462 | /** 463 | * Progress (0.0 to 1.0) 464 | */ 465 | @property (nonatomic, assign) float progress; 466 | 467 | /** 468 | * Indicator progress color. 469 | * Defaults to white [UIColor whiteColor] 470 | */ 471 | @property (nonatomic, MB_STRONG) UIColor *progressTintColor; 472 | 473 | /** 474 | * Indicator background (non-progress) color. 475 | * Defaults to translucent white (alpha 0.1) 476 | */ 477 | @property (nonatomic, MB_STRONG) UIColor *backgroundTintColor; 478 | 479 | /* 480 | * Display mode - NO = round or YES = annular. Defaults to round. 481 | */ 482 | @property (nonatomic, assign, getter = isAnnular) BOOL annular; 483 | 484 | @end 485 | 486 | 487 | /** 488 | * A flat bar progress view. 489 | */ 490 | @interface MBBarProgressView : UIView 491 | 492 | /** 493 | * Progress (0.0 to 1.0) 494 | */ 495 | @property (nonatomic, assign) float progress; 496 | 497 | /** 498 | * Bar border line color. 499 | * Defaults to white [UIColor whiteColor]. 500 | */ 501 | @property (nonatomic, MB_STRONG) UIColor *lineColor; 502 | 503 | /** 504 | * Bar background color. 505 | * Defaults to clear [UIColor clearColor]; 506 | */ 507 | @property (nonatomic, MB_STRONG) UIColor *progressRemainingColor; 508 | 509 | /** 510 | * Bar progress color. 511 | * Defaults to white [UIColor whiteColor]. 512 | */ 513 | @property (nonatomic, MB_STRONG) UIColor *progressColor; 514 | 515 | @end 516 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/MBProgressHUD/MBProgressHUD.m: -------------------------------------------------------------------------------- 1 | // 2 | // MBProgressHUD.m 3 | // Version 0.9 4 | // Created by Matej Bukovinski on 2.4.09. 5 | // 6 | 7 | #import "MBProgressHUD.h" 8 | #import 9 | 10 | 11 | #if __has_feature(objc_arc) 12 | #define MB_AUTORELEASE(exp) exp 13 | #define MB_RELEASE(exp) exp 14 | #define MB_RETAIN(exp) exp 15 | #else 16 | #define MB_AUTORELEASE(exp) [exp autorelease] 17 | #define MB_RELEASE(exp) [exp release] 18 | #define MB_RETAIN(exp) [exp retain] 19 | #endif 20 | 21 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 22 | #define MBLabelAlignmentCenter NSTextAlignmentCenter 23 | #else 24 | #define MBLabelAlignmentCenter UITextAlignmentCenter 25 | #endif 26 | 27 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 28 | #define MB_TEXTSIZE(text, font) [text length] > 0 ? [text \ 29 | sizeWithAttributes:@{NSFontAttributeName:font}] : CGSizeZero; 30 | #else 31 | #define MB_TEXTSIZE(text, font) [text length] > 0 ? [text sizeWithFont:font] : CGSizeZero; 32 | #endif 33 | 34 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 35 | #define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] > 0 ? [text \ 36 | boundingRectWithSize:maxSize options:(NSStringDrawingUsesLineFragmentOrigin) \ 37 | attributes:@{NSFontAttributeName:font} context:nil].size : CGSizeZero; 38 | #else 39 | #define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] > 0 ? [text \ 40 | sizeWithFont:font constrainedToSize:maxSize lineBreakMode:mode] : CGSizeZero; 41 | #endif 42 | 43 | #ifndef kCFCoreFoundationVersionNumber_iOS_7_0 44 | #define kCFCoreFoundationVersionNumber_iOS_7_0 847.20 45 | #endif 46 | 47 | #ifndef kCFCoreFoundationVersionNumber_iOS_8_0 48 | #define kCFCoreFoundationVersionNumber_iOS_8_0 1129.15 49 | #endif 50 | 51 | 52 | static const CGFloat kPadding = 4.f; 53 | static const CGFloat kLabelFontSize = 16.f; 54 | static const CGFloat kDetailsLabelFontSize = 12.f; 55 | 56 | 57 | @interface MBProgressHUD () { 58 | BOOL useAnimation; 59 | SEL methodForExecution; 60 | id targetForExecution; 61 | id objectForExecution; 62 | UILabel *label; 63 | UILabel *detailsLabel; 64 | BOOL isFinished; 65 | CGAffineTransform rotationTransform; 66 | } 67 | 68 | @property (atomic, MB_STRONG) UIView *indicator; 69 | @property (atomic, MB_STRONG) NSTimer *graceTimer; 70 | @property (atomic, MB_STRONG) NSTimer *minShowTimer; 71 | @property (atomic, MB_STRONG) NSDate *showStarted; 72 | 73 | 74 | @end 75 | 76 | 77 | @implementation MBProgressHUD 78 | 79 | #pragma mark - Properties 80 | 81 | @synthesize animationType; 82 | @synthesize delegate; 83 | @synthesize opacity; 84 | @synthesize color; 85 | @synthesize labelFont; 86 | @synthesize labelColor; 87 | @synthesize detailsLabelFont; 88 | @synthesize detailsLabelColor; 89 | @synthesize indicator; 90 | @synthesize xOffset; 91 | @synthesize yOffset; 92 | @synthesize minSize; 93 | @synthesize square; 94 | @synthesize margin; 95 | @synthesize dimBackground; 96 | @synthesize graceTime; 97 | @synthesize minShowTime; 98 | @synthesize graceTimer; 99 | @synthesize minShowTimer; 100 | @synthesize taskInProgress; 101 | @synthesize removeFromSuperViewOnHide; 102 | @synthesize customView; 103 | @synthesize showStarted; 104 | @synthesize mode; 105 | @synthesize labelText; 106 | @synthesize detailsLabelText; 107 | @synthesize progress; 108 | @synthesize size; 109 | @synthesize activityIndicatorColor; 110 | #if NS_BLOCKS_AVAILABLE 111 | @synthesize completionBlock; 112 | #endif 113 | 114 | #pragma mark - Class methods 115 | 116 | + (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated { 117 | MBProgressHUD *hud = [[self alloc] initWithView:view]; 118 | [view addSubview:hud]; 119 | [hud show:animated]; 120 | return MB_AUTORELEASE(hud); 121 | } 122 | 123 | + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated { 124 | MBProgressHUD *hud = [self HUDForView:view]; 125 | if (hud != nil) { 126 | hud.removeFromSuperViewOnHide = YES; 127 | [hud hide:animated]; 128 | return YES; 129 | } 130 | return NO; 131 | } 132 | 133 | + (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated { 134 | NSArray *huds = [MBProgressHUD allHUDsForView:view]; 135 | for (MBProgressHUD *hud in huds) { 136 | hud.removeFromSuperViewOnHide = YES; 137 | [hud hide:animated]; 138 | } 139 | return [huds count]; 140 | } 141 | 142 | + (MB_INSTANCETYPE)HUDForView:(UIView *)view { 143 | NSEnumerator *subviewsEnum = [view.subviews reverseObjectEnumerator]; 144 | for (UIView *subview in subviewsEnum) { 145 | if ([subview isKindOfClass:self]) { 146 | return (MBProgressHUD *)subview; 147 | } 148 | } 149 | return nil; 150 | } 151 | 152 | + (NSArray *)allHUDsForView:(UIView *)view { 153 | NSMutableArray *huds = [NSMutableArray array]; 154 | NSArray *subviews = view.subviews; 155 | for (UIView *aView in subviews) { 156 | if ([aView isKindOfClass:self]) { 157 | [huds addObject:aView]; 158 | } 159 | } 160 | return [NSArray arrayWithArray:huds]; 161 | } 162 | 163 | #pragma mark - Lifecycle 164 | 165 | - (id)initWithFrame:(CGRect)frame { 166 | self = [super initWithFrame:frame]; 167 | if (self) { 168 | // Set default values for properties 169 | self.animationType = MBProgressHUDAnimationFade; 170 | self.mode = MBProgressHUDModeIndeterminate; 171 | self.labelText = nil; 172 | self.detailsLabelText = nil; 173 | self.opacity = 0.8f; 174 | self.color = nil; 175 | self.labelFont = [UIFont boldSystemFontOfSize:kLabelFontSize]; 176 | self.labelColor = [UIColor whiteColor]; 177 | self.detailsLabelFont = [UIFont boldSystemFontOfSize:kDetailsLabelFontSize]; 178 | self.detailsLabelColor = [UIColor whiteColor]; 179 | self.activityIndicatorColor = [UIColor whiteColor]; 180 | self.xOffset = 0.0f; 181 | self.yOffset = 0.0f; 182 | self.dimBackground = NO; 183 | self.margin = 20.0f; 184 | self.cornerRadius = 10.0f; 185 | self.graceTime = 0.0f; 186 | self.minShowTime = 0.0f; 187 | self.removeFromSuperViewOnHide = NO; 188 | self.minSize = CGSizeZero; 189 | self.square = NO; 190 | self.contentMode = UIViewContentModeCenter; 191 | self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin 192 | | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; 193 | 194 | // Transparent background 195 | self.opaque = NO; 196 | self.backgroundColor = [UIColor clearColor]; 197 | // Make it invisible for now 198 | self.alpha = 0.0f; 199 | 200 | taskInProgress = NO; 201 | rotationTransform = CGAffineTransformIdentity; 202 | 203 | [self setupLabels]; 204 | [self updateIndicators]; 205 | [self registerForKVO]; 206 | [self registerForNotifications]; 207 | } 208 | return self; 209 | } 210 | 211 | - (id)initWithView:(UIView *)view { 212 | NSAssert(view, @"View must not be nil."); 213 | return [self initWithFrame:view.bounds]; 214 | } 215 | 216 | - (id)initWithWindow:(UIWindow *)window { 217 | return [self initWithView:window]; 218 | } 219 | 220 | - (void)dealloc { 221 | [self unregisterFromNotifications]; 222 | [self unregisterFromKVO]; 223 | #if !__has_feature(objc_arc) 224 | [color release]; 225 | [indicator release]; 226 | [label release]; 227 | [detailsLabel release]; 228 | [labelText release]; 229 | [detailsLabelText release]; 230 | [graceTimer release]; 231 | [minShowTimer release]; 232 | [showStarted release]; 233 | [customView release]; 234 | [labelFont release]; 235 | [labelColor release]; 236 | [detailsLabelFont release]; 237 | [detailsLabelColor release]; 238 | #if NS_BLOCKS_AVAILABLE 239 | [completionBlock release]; 240 | #endif 241 | [super dealloc]; 242 | #endif 243 | } 244 | 245 | #pragma mark - Show & hide 246 | 247 | - (void)show:(BOOL)animated { 248 | useAnimation = animated; 249 | // If the grace time is set postpone the HUD display 250 | if (self.graceTime > 0.0) { 251 | self.graceTimer = [NSTimer scheduledTimerWithTimeInterval:self.graceTime target:self 252 | selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO]; 253 | } 254 | // ... otherwise show the HUD imediately 255 | else { 256 | [self setNeedsDisplay]; 257 | [self showUsingAnimation:useAnimation]; 258 | } 259 | } 260 | 261 | - (void)hide:(BOOL)animated { 262 | useAnimation = animated; 263 | // If the minShow time is set, calculate how long the hud was shown, 264 | // and pospone the hiding operation if necessary 265 | if (self.minShowTime > 0.0 && showStarted) { 266 | NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:showStarted]; 267 | if (interv < self.minShowTime) { 268 | self.minShowTimer = [NSTimer scheduledTimerWithTimeInterval:(self.minShowTime - interv) target:self 269 | selector:@selector(handleMinShowTimer:) userInfo:nil repeats:NO]; 270 | return; 271 | } 272 | } 273 | // ... otherwise hide the HUD immediately 274 | [self hideUsingAnimation:useAnimation]; 275 | } 276 | 277 | - (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay { 278 | [self performSelector:@selector(hideDelayed:) withObject:[NSNumber numberWithBool:animated] afterDelay:delay]; 279 | } 280 | 281 | - (void)hideDelayed:(NSNumber *)animated { 282 | [self hide:[animated boolValue]]; 283 | } 284 | 285 | #pragma mark - Timer callbacks 286 | 287 | - (void)handleGraceTimer:(NSTimer *)theTimer { 288 | // Show the HUD only if the task is still running 289 | if (taskInProgress) { 290 | [self setNeedsDisplay]; 291 | [self showUsingAnimation:useAnimation]; 292 | } 293 | } 294 | 295 | - (void)handleMinShowTimer:(NSTimer *)theTimer { 296 | [self hideUsingAnimation:useAnimation]; 297 | } 298 | 299 | #pragma mark - View Hierrarchy 300 | 301 | - (BOOL)shouldPerformOrientationTransform { 302 | BOOL isPreiOS8 = NSFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_8_0; 303 | // prior to iOS8 code needs to take care of rotation if it is being added to the window 304 | return isPreiOS8 && [self.superview isKindOfClass:[UIWindow class]]; 305 | } 306 | 307 | - (void)didMoveToSuperview { 308 | if ([self shouldPerformOrientationTransform]) { 309 | [self setTransformForCurrentOrientation:NO]; 310 | } 311 | } 312 | 313 | #pragma mark - Internal show & hide operations 314 | 315 | - (void)showUsingAnimation:(BOOL)animated { 316 | if (animated && animationType == MBProgressHUDAnimationZoomIn) { 317 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f)); 318 | } else if (animated && animationType == MBProgressHUDAnimationZoomOut) { 319 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f)); 320 | } 321 | self.showStarted = [NSDate date]; 322 | // Fade in 323 | if (animated) { 324 | [UIView beginAnimations:nil context:NULL]; 325 | [UIView setAnimationDuration:0.30]; 326 | self.alpha = 1.0f; 327 | if (animationType == MBProgressHUDAnimationZoomIn || animationType == MBProgressHUDAnimationZoomOut) { 328 | self.transform = rotationTransform; 329 | } 330 | [UIView commitAnimations]; 331 | } 332 | else { 333 | self.alpha = 1.0f; 334 | } 335 | } 336 | 337 | - (void)hideUsingAnimation:(BOOL)animated { 338 | // Fade out 339 | if (animated && showStarted) { 340 | [UIView beginAnimations:nil context:NULL]; 341 | [UIView setAnimationDuration:0.30]; 342 | [UIView setAnimationDelegate:self]; 343 | [UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)]; 344 | // 0.02 prevents the hud from passing through touches during the animation the hud will get completely hidden 345 | // in the done method 346 | if (animationType == MBProgressHUDAnimationZoomIn) { 347 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f)); 348 | } else if (animationType == MBProgressHUDAnimationZoomOut) { 349 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f)); 350 | } 351 | 352 | self.alpha = 0.02f; 353 | [UIView commitAnimations]; 354 | } 355 | else { 356 | self.alpha = 0.0f; 357 | [self done]; 358 | } 359 | self.showStarted = nil; 360 | } 361 | 362 | - (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void*)context { 363 | [self done]; 364 | } 365 | 366 | - (void)done { 367 | [NSObject cancelPreviousPerformRequestsWithTarget:self]; 368 | isFinished = YES; 369 | self.alpha = 0.0f; 370 | if (removeFromSuperViewOnHide) { 371 | [self removeFromSuperview]; 372 | } 373 | #if NS_BLOCKS_AVAILABLE 374 | if (self.completionBlock) { 375 | self.completionBlock(); 376 | self.completionBlock = NULL; 377 | } 378 | #endif 379 | if ([delegate respondsToSelector:@selector(hudWasHidden:)]) { 380 | [delegate performSelector:@selector(hudWasHidden:) withObject:self]; 381 | } 382 | } 383 | 384 | #pragma mark - Threading 385 | 386 | - (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated { 387 | methodForExecution = method; 388 | targetForExecution = MB_RETAIN(target); 389 | objectForExecution = MB_RETAIN(object); 390 | // Launch execution in new thread 391 | self.taskInProgress = YES; 392 | [NSThread detachNewThreadSelector:@selector(launchExecution) toTarget:self withObject:nil]; 393 | // Show HUD view 394 | [self show:animated]; 395 | } 396 | 397 | #if NS_BLOCKS_AVAILABLE 398 | 399 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block { 400 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 401 | [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:NULL]; 402 | } 403 | 404 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(void (^)())completion { 405 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 406 | [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:completion]; 407 | } 408 | 409 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue { 410 | [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:NULL]; 411 | } 412 | 413 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue 414 | completionBlock:(MBProgressHUDCompletionBlock)completion { 415 | self.taskInProgress = YES; 416 | self.completionBlock = completion; 417 | dispatch_async(queue, ^(void) { 418 | block(); 419 | dispatch_async(dispatch_get_main_queue(), ^(void) { 420 | [self cleanUp]; 421 | }); 422 | }); 423 | [self show:animated]; 424 | } 425 | 426 | #endif 427 | 428 | - (void)launchExecution { 429 | @autoreleasepool { 430 | #pragma clang diagnostic push 431 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 432 | // Start executing the requested task 433 | [targetForExecution performSelector:methodForExecution withObject:objectForExecution]; 434 | #pragma clang diagnostic pop 435 | // Task completed, update view in main thread (note: view operations should 436 | // be done only in the main thread) 437 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO]; 438 | } 439 | } 440 | 441 | - (void)cleanUp { 442 | taskInProgress = NO; 443 | #if !__has_feature(objc_arc) 444 | [targetForExecution release]; 445 | [objectForExecution release]; 446 | #else 447 | targetForExecution = nil; 448 | objectForExecution = nil; 449 | #endif 450 | [self hide:useAnimation]; 451 | } 452 | 453 | #pragma mark - UI 454 | 455 | - (void)setupLabels { 456 | label = [[UILabel alloc] initWithFrame:self.bounds]; 457 | label.adjustsFontSizeToFitWidth = NO; 458 | label.textAlignment = MBLabelAlignmentCenter; 459 | label.opaque = NO; 460 | label.backgroundColor = [UIColor clearColor]; 461 | label.textColor = self.labelColor; 462 | label.font = self.labelFont; 463 | label.text = self.labelText; 464 | [self addSubview:label]; 465 | 466 | detailsLabel = [[UILabel alloc] initWithFrame:self.bounds]; 467 | detailsLabel.font = self.detailsLabelFont; 468 | detailsLabel.adjustsFontSizeToFitWidth = NO; 469 | detailsLabel.textAlignment = MBLabelAlignmentCenter; 470 | detailsLabel.opaque = NO; 471 | detailsLabel.backgroundColor = [UIColor clearColor]; 472 | detailsLabel.textColor = self.detailsLabelColor; 473 | detailsLabel.numberOfLines = 0; 474 | detailsLabel.font = self.detailsLabelFont; 475 | detailsLabel.text = self.detailsLabelText; 476 | [self addSubview:detailsLabel]; 477 | } 478 | 479 | - (void)updateIndicators { 480 | 481 | BOOL isActivityIndicator = [indicator isKindOfClass:[UIActivityIndicatorView class]]; 482 | BOOL isRoundIndicator = [indicator isKindOfClass:[MBRoundProgressView class]]; 483 | 484 | if (mode == MBProgressHUDModeIndeterminate) { 485 | if (!isActivityIndicator) { 486 | // Update to indeterminate indicator 487 | [indicator removeFromSuperview]; 488 | self.indicator = MB_AUTORELEASE([[UIActivityIndicatorView alloc] 489 | initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]); 490 | [(UIActivityIndicatorView *)indicator startAnimating]; 491 | [self addSubview:indicator]; 492 | } 493 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 494 | [(UIActivityIndicatorView *)indicator setColor:self.activityIndicatorColor]; 495 | #endif 496 | } 497 | else if (mode == MBProgressHUDModeDeterminateHorizontalBar) { 498 | // Update to bar determinate indicator 499 | [indicator removeFromSuperview]; 500 | self.indicator = MB_AUTORELEASE([[MBBarProgressView alloc] init]); 501 | [self addSubview:indicator]; 502 | } 503 | else if (mode == MBProgressHUDModeDeterminate || mode == MBProgressHUDModeAnnularDeterminate) { 504 | if (!isRoundIndicator) { 505 | // Update to determinante indicator 506 | [indicator removeFromSuperview]; 507 | self.indicator = MB_AUTORELEASE([[MBRoundProgressView alloc] init]); 508 | [self addSubview:indicator]; 509 | } 510 | if (mode == MBProgressHUDModeAnnularDeterminate) { 511 | [(MBRoundProgressView *)indicator setAnnular:YES]; 512 | } 513 | } 514 | else if (mode == MBProgressHUDModeCustomView && customView != indicator) { 515 | // Update custom view indicator 516 | [indicator removeFromSuperview]; 517 | self.indicator = customView; 518 | [self addSubview:indicator]; 519 | } else if (mode == MBProgressHUDModeText) { 520 | [indicator removeFromSuperview]; 521 | self.indicator = nil; 522 | } 523 | } 524 | 525 | #pragma mark - Layout 526 | 527 | - (void)layoutSubviews { 528 | [super layoutSubviews]; 529 | 530 | // Entirely cover the parent view 531 | UIView *parent = self.superview; 532 | if (parent) { 533 | self.frame = parent.bounds; 534 | } 535 | CGRect bounds = self.bounds; 536 | 537 | // Determine the total widt and height needed 538 | CGFloat maxWidth = bounds.size.width - 4 * margin; 539 | CGSize totalSize = CGSizeZero; 540 | 541 | CGRect indicatorF = indicator.bounds; 542 | indicatorF.size.width = MIN(indicatorF.size.width, maxWidth); 543 | totalSize.width = MAX(totalSize.width, indicatorF.size.width); 544 | totalSize.height += indicatorF.size.height; 545 | 546 | CGSize labelSize = MB_TEXTSIZE(label.text, label.font); 547 | labelSize.width = MIN(labelSize.width, maxWidth); 548 | totalSize.width = MAX(totalSize.width, labelSize.width); 549 | totalSize.height += labelSize.height; 550 | if (labelSize.height > 0.f && indicatorF.size.height > 0.f) { 551 | totalSize.height += kPadding; 552 | } 553 | 554 | CGFloat remainingHeight = bounds.size.height - totalSize.height - kPadding - 4 * margin; 555 | CGSize maxSize = CGSizeMake(maxWidth, remainingHeight); 556 | CGSize detailsLabelSize = MB_MULTILINE_TEXTSIZE(detailsLabel.text, detailsLabel.font, maxSize, detailsLabel.lineBreakMode); 557 | totalSize.width = MAX(totalSize.width, detailsLabelSize.width); 558 | totalSize.height += detailsLabelSize.height; 559 | if (detailsLabelSize.height > 0.f && (indicatorF.size.height > 0.f || labelSize.height > 0.f)) { 560 | totalSize.height += kPadding; 561 | } 562 | 563 | totalSize.width += 2 * margin; 564 | totalSize.height += 2 * margin; 565 | 566 | // Position elements 567 | CGFloat yPos = round(((bounds.size.height - totalSize.height) / 2)) + margin + yOffset; 568 | CGFloat xPos = xOffset; 569 | indicatorF.origin.y = yPos; 570 | indicatorF.origin.x = round((bounds.size.width - indicatorF.size.width) / 2) + xPos; 571 | indicator.frame = indicatorF; 572 | yPos += indicatorF.size.height; 573 | 574 | if (labelSize.height > 0.f && indicatorF.size.height > 0.f) { 575 | yPos += kPadding; 576 | } 577 | CGRect labelF; 578 | labelF.origin.y = yPos; 579 | labelF.origin.x = round((bounds.size.width - labelSize.width) / 2) + xPos; 580 | labelF.size = labelSize; 581 | label.frame = labelF; 582 | yPos += labelF.size.height; 583 | 584 | if (detailsLabelSize.height > 0.f && (indicatorF.size.height > 0.f || labelSize.height > 0.f)) { 585 | yPos += kPadding; 586 | } 587 | CGRect detailsLabelF; 588 | detailsLabelF.origin.y = yPos; 589 | detailsLabelF.origin.x = round((bounds.size.width - detailsLabelSize.width) / 2) + xPos; 590 | detailsLabelF.size = detailsLabelSize; 591 | detailsLabel.frame = detailsLabelF; 592 | 593 | // Enforce minsize and quare rules 594 | if (square) { 595 | CGFloat max = MAX(totalSize.width, totalSize.height); 596 | if (max <= bounds.size.width - 2 * margin) { 597 | totalSize.width = max; 598 | } 599 | if (max <= bounds.size.height - 2 * margin) { 600 | totalSize.height = max; 601 | } 602 | } 603 | if (totalSize.width < minSize.width) { 604 | totalSize.width = minSize.width; 605 | } 606 | if (totalSize.height < minSize.height) { 607 | totalSize.height = minSize.height; 608 | } 609 | 610 | size = totalSize; 611 | } 612 | 613 | #pragma mark BG Drawing 614 | 615 | - (void)drawRect:(CGRect)rect { 616 | 617 | CGContextRef context = UIGraphicsGetCurrentContext(); 618 | UIGraphicsPushContext(context); 619 | 620 | if (self.dimBackground) { 621 | //Gradient colours 622 | size_t gradLocationsNum = 2; 623 | CGFloat gradLocations[2] = {0.0f, 1.0f}; 624 | CGFloat gradColors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.75f}; 625 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 626 | CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum); 627 | CGColorSpaceRelease(colorSpace); 628 | //Gradient center 629 | CGPoint gradCenter= CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); 630 | //Gradient radius 631 | float gradRadius = MIN(self.bounds.size.width , self.bounds.size.height) ; 632 | //Gradient draw 633 | CGContextDrawRadialGradient (context, gradient, gradCenter, 634 | 0, gradCenter, gradRadius, 635 | kCGGradientDrawsAfterEndLocation); 636 | CGGradientRelease(gradient); 637 | } 638 | 639 | // Set background rect color 640 | if (self.color) { 641 | CGContextSetFillColorWithColor(context, self.color.CGColor); 642 | } else { 643 | CGContextSetGrayFillColor(context, 0.0f, self.opacity); 644 | } 645 | 646 | 647 | // Center HUD 648 | CGRect allRect = self.bounds; 649 | // Draw rounded HUD backgroud rect 650 | CGRect boxRect = CGRectMake(round((allRect.size.width - size.width) / 2) + self.xOffset, 651 | round((allRect.size.height - size.height) / 2) + self.yOffset, size.width, size.height); 652 | float radius = self.cornerRadius; 653 | CGContextBeginPath(context); 654 | CGContextMoveToPoint(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect)); 655 | CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMinY(boxRect) + radius, radius, 3 * (float)M_PI / 2, 0, 0); 656 | CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMaxY(boxRect) - radius, radius, 0, (float)M_PI / 2, 0); 657 | CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMaxY(boxRect) - radius, radius, (float)M_PI / 2, (float)M_PI, 0); 658 | CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect) + radius, radius, (float)M_PI, 3 * (float)M_PI / 2, 0); 659 | CGContextClosePath(context); 660 | CGContextFillPath(context); 661 | 662 | UIGraphicsPopContext(); 663 | } 664 | 665 | #pragma mark - KVO 666 | 667 | - (void)registerForKVO { 668 | for (NSString *keyPath in [self observableKeypaths]) { 669 | [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; 670 | } 671 | } 672 | 673 | - (void)unregisterFromKVO { 674 | for (NSString *keyPath in [self observableKeypaths]) { 675 | [self removeObserver:self forKeyPath:keyPath]; 676 | } 677 | } 678 | 679 | - (NSArray *)observableKeypaths { 680 | return [NSArray arrayWithObjects:@"mode", @"customView", @"labelText", @"labelFont", @"labelColor", 681 | @"detailsLabelText", @"detailsLabelFont", @"detailsLabelColor", @"progress", @"activityIndicatorColor", nil]; 682 | } 683 | 684 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 685 | if (![NSThread isMainThread]) { 686 | [self performSelectorOnMainThread:@selector(updateUIForKeypath:) withObject:keyPath waitUntilDone:NO]; 687 | } else { 688 | [self updateUIForKeypath:keyPath]; 689 | } 690 | } 691 | 692 | - (void)updateUIForKeypath:(NSString *)keyPath { 693 | if ([keyPath isEqualToString:@"mode"] || [keyPath isEqualToString:@"customView"] || 694 | [keyPath isEqualToString:@"activityIndicatorColor"]) { 695 | [self updateIndicators]; 696 | } else if ([keyPath isEqualToString:@"labelText"]) { 697 | label.text = self.labelText; 698 | } else if ([keyPath isEqualToString:@"labelFont"]) { 699 | label.font = self.labelFont; 700 | } else if ([keyPath isEqualToString:@"labelColor"]) { 701 | label.textColor = self.labelColor; 702 | } else if ([keyPath isEqualToString:@"detailsLabelText"]) { 703 | detailsLabel.text = self.detailsLabelText; 704 | } else if ([keyPath isEqualToString:@"detailsLabelFont"]) { 705 | detailsLabel.font = self.detailsLabelFont; 706 | } else if ([keyPath isEqualToString:@"detailsLabelColor"]) { 707 | detailsLabel.textColor = self.detailsLabelColor; 708 | } else if ([keyPath isEqualToString:@"progress"]) { 709 | if ([indicator respondsToSelector:@selector(setProgress:)]) { 710 | [(id)indicator setValue:@(progress) forKey:@"progress"]; 711 | } 712 | return; 713 | } 714 | [self setNeedsLayout]; 715 | [self setNeedsDisplay]; 716 | } 717 | 718 | #pragma mark - Notifications 719 | 720 | - (void)registerForNotifications { 721 | NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 722 | 723 | [nc addObserver:self selector:@selector(statusBarOrientationDidChange:) 724 | name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; 725 | } 726 | 727 | - (void)unregisterFromNotifications { 728 | NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 729 | [nc removeObserver:self name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; 730 | } 731 | 732 | - (void)statusBarOrientationDidChange:(NSNotification *)notification { 733 | UIView *superview = self.superview; 734 | if (!superview) { 735 | return; 736 | } else if ([self shouldPerformOrientationTransform]) { 737 | [self setTransformForCurrentOrientation:YES]; 738 | } else { 739 | self.frame = self.superview.bounds; 740 | [self setNeedsDisplay]; 741 | } 742 | } 743 | 744 | - (void)setTransformForCurrentOrientation:(BOOL)animated { 745 | // Stay in sync with the superview 746 | if (self.superview) { 747 | self.bounds = self.superview.bounds; 748 | [self setNeedsDisplay]; 749 | } 750 | 751 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 752 | CGFloat radians = 0; 753 | if (UIInterfaceOrientationIsLandscape(orientation)) { 754 | if (orientation == UIInterfaceOrientationLandscapeLeft) { radians = -(CGFloat)M_PI_2; } 755 | else { radians = (CGFloat)M_PI_2; } 756 | // Window coordinates differ! 757 | self.bounds = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.width); 758 | } else { 759 | if (orientation == UIInterfaceOrientationPortraitUpsideDown) { radians = (CGFloat)M_PI; } 760 | else { radians = 0; } 761 | } 762 | rotationTransform = CGAffineTransformMakeRotation(radians); 763 | 764 | if (animated) { 765 | [UIView beginAnimations:nil context:nil]; 766 | [UIView setAnimationDuration:0.3]; 767 | } 768 | [self setTransform:rotationTransform]; 769 | if (animated) { 770 | [UIView commitAnimations]; 771 | } 772 | } 773 | 774 | @end 775 | 776 | 777 | @implementation MBRoundProgressView 778 | 779 | #pragma mark - Lifecycle 780 | 781 | - (id)init { 782 | return [self initWithFrame:CGRectMake(0.f, 0.f, 37.f, 37.f)]; 783 | } 784 | 785 | - (id)initWithFrame:(CGRect)frame { 786 | self = [super initWithFrame:frame]; 787 | if (self) { 788 | self.backgroundColor = [UIColor clearColor]; 789 | self.opaque = NO; 790 | _progress = 0.f; 791 | _annular = NO; 792 | _progressTintColor = [[UIColor alloc] initWithWhite:1.f alpha:1.f]; 793 | _backgroundTintColor = [[UIColor alloc] initWithWhite:1.f alpha:.1f]; 794 | [self registerForKVO]; 795 | } 796 | return self; 797 | } 798 | 799 | - (void)dealloc { 800 | [self unregisterFromKVO]; 801 | #if !__has_feature(objc_arc) 802 | [_progressTintColor release]; 803 | [_backgroundTintColor release]; 804 | [super dealloc]; 805 | #endif 806 | } 807 | 808 | #pragma mark - Drawing 809 | 810 | - (void)drawRect:(CGRect)rect { 811 | 812 | CGRect allRect = self.bounds; 813 | CGRect circleRect = CGRectInset(allRect, 2.0f, 2.0f); 814 | CGContextRef context = UIGraphicsGetCurrentContext(); 815 | 816 | if (_annular) { 817 | // Draw background 818 | BOOL isPreiOS7 = NSFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_7_0; 819 | CGFloat lineWidth = isPreiOS7 ? 5.f : 2.f; 820 | UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath]; 821 | processBackgroundPath.lineWidth = lineWidth; 822 | processBackgroundPath.lineCapStyle = kCGLineCapButt; 823 | CGPoint center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); 824 | CGFloat radius = (self.bounds.size.width - lineWidth)/2; 825 | CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees 826 | CGFloat endAngle = (2 * (float)M_PI) + startAngle; 827 | [processBackgroundPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; 828 | [_backgroundTintColor set]; 829 | [processBackgroundPath stroke]; 830 | // Draw progress 831 | UIBezierPath *processPath = [UIBezierPath bezierPath]; 832 | processPath.lineCapStyle = isPreiOS7 ? kCGLineCapRound : kCGLineCapSquare; 833 | processPath.lineWidth = lineWidth; 834 | endAngle = (self.progress * 2 * (float)M_PI) + startAngle; 835 | [processPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; 836 | [_progressTintColor set]; 837 | [processPath stroke]; 838 | } else { 839 | // Draw background 840 | [_progressTintColor setStroke]; 841 | [_backgroundTintColor setFill]; 842 | CGContextSetLineWidth(context, 2.0f); 843 | CGContextFillEllipseInRect(context, circleRect); 844 | CGContextStrokeEllipseInRect(context, circleRect); 845 | // Draw progress 846 | CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2); 847 | CGFloat radius = (allRect.size.width - 4) / 2; 848 | CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees 849 | CGFloat endAngle = (self.progress * 2 * (float)M_PI) + startAngle; 850 | CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f); // white 851 | CGContextMoveToPoint(context, center.x, center.y); 852 | CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0); 853 | CGContextClosePath(context); 854 | CGContextFillPath(context); 855 | } 856 | } 857 | 858 | #pragma mark - KVO 859 | 860 | - (void)registerForKVO { 861 | for (NSString *keyPath in [self observableKeypaths]) { 862 | [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; 863 | } 864 | } 865 | 866 | - (void)unregisterFromKVO { 867 | for (NSString *keyPath in [self observableKeypaths]) { 868 | [self removeObserver:self forKeyPath:keyPath]; 869 | } 870 | } 871 | 872 | - (NSArray *)observableKeypaths { 873 | return [NSArray arrayWithObjects:@"progressTintColor", @"backgroundTintColor", @"progress", @"annular", nil]; 874 | } 875 | 876 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 877 | [self setNeedsDisplay]; 878 | } 879 | 880 | @end 881 | 882 | 883 | @implementation MBBarProgressView 884 | 885 | #pragma mark - Lifecycle 886 | 887 | - (id)init { 888 | return [self initWithFrame:CGRectMake(.0f, .0f, 120.0f, 20.0f)]; 889 | } 890 | 891 | - (id)initWithFrame:(CGRect)frame { 892 | self = [super initWithFrame:frame]; 893 | if (self) { 894 | _progress = 0.f; 895 | _lineColor = [UIColor whiteColor]; 896 | _progressColor = [UIColor whiteColor]; 897 | _progressRemainingColor = [UIColor clearColor]; 898 | self.backgroundColor = [UIColor clearColor]; 899 | self.opaque = NO; 900 | [self registerForKVO]; 901 | } 902 | return self; 903 | } 904 | 905 | - (void)dealloc { 906 | [self unregisterFromKVO]; 907 | #if !__has_feature(objc_arc) 908 | [_lineColor release]; 909 | [_progressColor release]; 910 | [_progressRemainingColor release]; 911 | [super dealloc]; 912 | #endif 913 | } 914 | 915 | #pragma mark - Drawing 916 | 917 | - (void)drawRect:(CGRect)rect { 918 | CGContextRef context = UIGraphicsGetCurrentContext(); 919 | 920 | CGContextSetLineWidth(context, 2); 921 | CGContextSetStrokeColorWithColor(context,[_lineColor CGColor]); 922 | CGContextSetFillColorWithColor(context, [_progressRemainingColor CGColor]); 923 | 924 | // Draw background 925 | float radius = (rect.size.height / 2) - 2; 926 | CGContextMoveToPoint(context, 2, rect.size.height/2); 927 | CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius); 928 | CGContextAddLineToPoint(context, rect.size.width - radius - 2, 2); 929 | CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius); 930 | CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius); 931 | CGContextAddLineToPoint(context, radius + 2, rect.size.height - 2); 932 | CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius); 933 | CGContextFillPath(context); 934 | 935 | // Draw border 936 | CGContextMoveToPoint(context, 2, rect.size.height/2); 937 | CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius); 938 | CGContextAddLineToPoint(context, rect.size.width - radius - 2, 2); 939 | CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius); 940 | CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius); 941 | CGContextAddLineToPoint(context, radius + 2, rect.size.height - 2); 942 | CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius); 943 | CGContextStrokePath(context); 944 | 945 | CGContextSetFillColorWithColor(context, [_progressColor CGColor]); 946 | radius = radius - 2; 947 | float amount = self.progress * rect.size.width; 948 | 949 | // Progress in the middle area 950 | if (amount >= radius + 4 && amount <= (rect.size.width - radius - 4)) { 951 | CGContextMoveToPoint(context, 4, rect.size.height/2); 952 | CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); 953 | CGContextAddLineToPoint(context, amount, 4); 954 | CGContextAddLineToPoint(context, amount, radius + 4); 955 | 956 | CGContextMoveToPoint(context, 4, rect.size.height/2); 957 | CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); 958 | CGContextAddLineToPoint(context, amount, rect.size.height - 4); 959 | CGContextAddLineToPoint(context, amount, radius + 4); 960 | 961 | CGContextFillPath(context); 962 | } 963 | 964 | // Progress in the right arc 965 | else if (amount > radius + 4) { 966 | float x = amount - (rect.size.width - radius - 4); 967 | 968 | CGContextMoveToPoint(context, 4, rect.size.height/2); 969 | CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); 970 | CGContextAddLineToPoint(context, rect.size.width - radius - 4, 4); 971 | float angle = -acos(x/radius); 972 | if (isnan(angle)) angle = 0; 973 | CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, M_PI, angle, 0); 974 | CGContextAddLineToPoint(context, amount, rect.size.height/2); 975 | 976 | CGContextMoveToPoint(context, 4, rect.size.height/2); 977 | CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); 978 | CGContextAddLineToPoint(context, rect.size.width - radius - 4, rect.size.height - 4); 979 | angle = acos(x/radius); 980 | if (isnan(angle)) angle = 0; 981 | CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, -M_PI, angle, 1); 982 | CGContextAddLineToPoint(context, amount, rect.size.height/2); 983 | 984 | CGContextFillPath(context); 985 | } 986 | 987 | // Progress is in the left arc 988 | else if (amount < radius + 4 && amount > 0) { 989 | CGContextMoveToPoint(context, 4, rect.size.height/2); 990 | CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); 991 | CGContextAddLineToPoint(context, radius + 4, rect.size.height/2); 992 | 993 | CGContextMoveToPoint(context, 4, rect.size.height/2); 994 | CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); 995 | CGContextAddLineToPoint(context, radius + 4, rect.size.height/2); 996 | 997 | CGContextFillPath(context); 998 | } 999 | } 1000 | 1001 | #pragma mark - KVO 1002 | 1003 | - (void)registerForKVO { 1004 | for (NSString *keyPath in [self observableKeypaths]) { 1005 | [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; 1006 | } 1007 | } 1008 | 1009 | - (void)unregisterFromKVO { 1010 | for (NSString *keyPath in [self observableKeypaths]) { 1011 | [self removeObserver:self forKeyPath:keyPath]; 1012 | } 1013 | } 1014 | 1015 | - (NSArray *)observableKeypaths { 1016 | return [NSArray arrayWithObjects:@"lineColor", @"progressRemainingColor", @"progressColor", @"progress", nil]; 1017 | } 1018 | 1019 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 1020 | [self setNeedsDisplay]; 1021 | } 1022 | 1023 | @end 1024 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // CYPasswordViewDemo 4 | // 5 | // Created by cheny on 15/10/8. 6 | // Copyright © 2015年 zhssit. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // CYPasswordViewDemo 4 | // 5 | // Created by cheny on 15/10/8. 6 | // Copyright © 2015年 zhssit. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "CYPasswordView.h" 11 | #import "MBProgressHUD+MJ.h" 12 | 13 | #define kRequestTime 3.0f 14 | #define kDelay 1.0f 15 | 16 | @interface ViewController () 17 | 18 | @property (nonatomic, strong) CYPasswordView *passwordView; 19 | 20 | @end 21 | 22 | @implementation ViewController 23 | 24 | static BOOL flag = NO; 25 | 26 | - (void)viewDidLoad { 27 | [super viewDidLoad]; 28 | /** 注册取消按钮点击的通知 */ 29 | [CYNotificationCenter addObserver:self selector:@selector(cancel) name:CYPasswordViewCancleButtonClickNotification object:nil]; 30 | [CYNotificationCenter addObserver:self selector:@selector(forgetPWD) name:CYPasswordViewForgetPWDButtonClickNotification object:nil]; 31 | } 32 | 33 | - (void)dealloc { 34 | CYLog(@"cy =========== %@:我走了", [self class]); 35 | } 36 | 37 | - (void)cancel { 38 | CYLog(@"关闭密码框"); 39 | [MBProgressHUD showSuccess:@"关闭密码框"]; 40 | } 41 | 42 | - (void)forgetPWD { 43 | CYLog(@"忘记密码"); 44 | [MBProgressHUD showSuccess:@"忘记密码"]; 45 | } 46 | 47 | - (IBAction)showPasswordView:(id)sender { 48 | __weak ViewController *weakSelf = self; 49 | self.passwordView = [[CYPasswordView alloc] init]; 50 | self.passwordView.title = @"输入交易密码"; 51 | self.passwordView.loadingText = @"提交中..."; 52 | [self.passwordView showInView:self.view.window]; 53 | 54 | self.passwordView.finish = ^(NSString *password) { 55 | [weakSelf.passwordView hideKeyboard]; 56 | [weakSelf.passwordView startLoading]; 57 | CYLog(@"cy ========= 发送网络请求 pwd=%@", password); 58 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kRequestTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 59 | flag = !flag; 60 | if (flag) { 61 | CYLog(@"申购成功,跳转到成功页"); 62 | [MBProgressHUD showSuccess:@"申购成功,做一些处理"]; 63 | [weakSelf.passwordView requestComplete:YES message:@"申购成功,做一些处理"]; 64 | [weakSelf.passwordView stopLoading]; 65 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDelay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 66 | [weakSelf.passwordView hide]; 67 | }); 68 | } else { 69 | CYLog(@"申购失败,跳转到失败页"); 70 | [MBProgressHUD showError:@"申购失败,做一些处理"]; 71 | [weakSelf.passwordView requestComplete:NO message:@"申购失败,做一些处理"]; 72 | [weakSelf.passwordView stopLoading]; 73 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDelay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 74 | [weakSelf.passwordView hide]; 75 | }); 76 | 77 | } 78 | 79 | }); 80 | }; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /CYPasswordViewDemo/CYPasswordViewDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CYPasswordViewDemo 4 | // 5 | // Created by cheny on 15/10/8. 6 | // Copyright © 2015年 zhssit. 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 cheny 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 | ## CYPasswordView 2 | --- 3 | `CYPasswordView`是一个模仿支付宝输入支付密码的密码框。 4 | ### 一、说明 5 | --- 6 | * `CYPasswordView`是一个简单且实用的输入密码框 7 | * 具体用法主要参考Demo程序 8 | 9 | ### 二、使用方法 10 | --- 11 | #### 使用 CocoaPods 12 | `pod 'CYPasswordView'` 13 | 14 | #### 手动导入文件 15 | 1. 将`CYPasswordView`文件夹添加到项目中 16 | 2. 导入主头文件`#import "CYPasswordView.h"` 17 | 18 | ### 三、部分API的介绍 19 | --- 20 | * 实例化`CYPasswordView`对象 21 | ``` objc 22 | [[CYPasswordView alloc] init]; 23 | ``` 24 | * 弹出密码框 25 | ``` objc 26 | - (void)showInView:(UIView *)view; 27 | ``` 28 | 29 | * 密码输入完成的回调 30 | ``` objc 31 | @property (nonatomic, copy) void (^finish) (NSString *password); 32 | ``` 33 | * 隐藏键盘 34 | ``` objc 35 | - (void)hidenKeyboard; 36 | ``` 37 | * 隐藏密码框 38 | ``` objc 39 | - (void)hide; 40 | ``` 41 | * 开始加载(发送网络请求时,加载动画) 42 | ``` objc 43 | - (void)startLoading; 44 | ``` 45 | 46 | * 加载完成(暂停动画) 47 | ``` objc 48 | - (void)stopLoading; 49 | ``` 50 | 51 | * 请求完成 52 | ``` objc 53 | - (void)requestComplete:(BOOL)state; 54 | - (void)requestComplete:(BOOL)state message:(NSString *)message; 55 | ``` 56 | 57 | * 设置对话框标题 58 | ``` objc 59 | @property (nonatomic, copy) NSString *title; 60 | ``` 61 | 62 | ### 四、效果示例 63 | --- 64 | ![CYPasswordView](https://github.com/chernyog/CYPasswordView/blob/master/CYPasswordViewDemo/CYPasswordViewDemo/CYPasswordViewDemo.gif "CYPasswordView示例") --------------------------------------------------------------------------------