IOS-支付密码插件

仿支付宝的支付密码插件,先上四张效果图。

 以下代码,根据Masonry布局,若项目有Masonry库,根据文件命名,复制可直接用。

 PasswordView.h

#import <UIKit/UIKit.h>
#import "MZTTextField.h"

@interface PasswordView : UIView

//密码输入文本框
@property (nonatomic,strong) MZTTextField *passwordField;

@end

 PasswordView.m

/**
 设计思路:
 第一步:先创建控件:标题、取消按钮、一个输入框。
 第二步:再将输入框六等分,用分割线分开,这样看起来就有六个框了,再创建六个 密码点视图(就是黑圆点),位置根据输入框六等分来设置,添加到视图并全部hide,然后存放在一个数组里。
 第三步:每次输入密码,先将全部密码点全部hide,然后再根据输入密码的长度,一个一个的显示出来,比如密码输入到第四位,就利用循环将数组前四位的密码点hide设置为NO。这样删除也好处理。
 第四步:判断,显示动画。
 **/

#import "PasswordView.h"

//禁止复制、粘贴、全选、剪切等操作的输入框
#import "MZTTextField.h"

//输入密码后的等待和成功动画
#import "PaymentLoadingHUD.h"
#import "PaymentSuccessHUD.h"

#import <Masonry.h>

#define ScreenWidth [UIScreen mainScreen].bounds.size.width
#define ScreenHeight [UIScreen mainScreen].bounds.size.height

//密码位数
static NSInteger const DotsNumber = 6;

//密码点的宽和高  应该是等高等宽的正方形 方便设置为圆角
static CGFloat const DotWith_height = 12;

@interface PasswordView () <UITextFieldDelegate,UIAlertViewDelegate>

//标题
@property (nonatomic,strong) UILabel *title;

//取消按钮
@property (nonatomic,strong) UIButton *btn_cancel;

//忘记密码按钮
@property (nonatomic,strong) UIButton *forgetPassword;
//分割线
@property (nonatomic,strong) UIView *line;



//用来装密码点的数组,里面装的是view
@property (nonatomic,strong) NSMutableArray *passwordDotsArray;

//用户的默认支付密码
@property (nonatomic,strong) NSString *password;

@property (nonatomic,strong) UILabel *PaymentText;

@end

@implementation PasswordView

#pragma mark - 初始化密码、视图、数组
//重写初始化类方法
-(instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
        
        self.backgroundColor = [UIColor whiteColor];
        
        [self getPassword];
        
        //创建子控件,并添加到视图
        [self InitAllUI];
        
    }
    return self;
}

////获取支付密码
-(void)getPassword {
    self.password = @"131415";
}

-(void)InitAllUI {
    
    //标题
    self.title = [[UILabel alloc]init];
    self.title.text = @"请输入支付密码";
    self.title.textAlignment = NSTextAlignmentCenter;
    self.title.font = [UIFont systemFontOfSize:16];
    CGSize size = [self.title.text sizeWithAttributes:@{NSFontAttributeName:self.title.font}];
    [self addSubview:self.title];
    [self.title mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.mas_top).with.offset(15);
        make.centerX.equalTo(self.mas_centerX);
        make.size.mas_equalTo(CGSizeMake(size.width+10, size.height));
    }];
    
    //取消按钮
    self.btn_cancel = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.btn_cancel setImage:[UIImage imageNamed:@"箭头灰"] forState:UIControlStateNormal];
    [self.btn_cancel addTarget:self action:@selector(TakeUpPassword) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:self.btn_cancel];
    [self.btn_cancel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(self.title.mas_centerY);
        make.left.equalTo(self.mas_left).with.offset(10);
        make.size.mas_equalTo(CGSizeMake(28, 28));
    }];
    
    //分割线
    self.line = [UIView new];
    self.line.backgroundColor = [UIColor colorWithRed:222/255.0f green:222/255.0f blue:222/255.0f alpha:1];
    [self addSubview:self.line];
    [self.line mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.title.mas_bottom).with.offset(15);
        make.left.equalTo(self.mas_left);
        make.size.mas_equalTo(CGSizeMake(MZT_SCREEN_WIDTH, 1));
    }];
    
    
    //密码输入框
    self.passwordField = [[MZTTextField alloc]init];
    self.passwordField.backgroundColor = [UIColor whiteColor];
    self.passwordField.alpha = 0.8;
    self.passwordField.textColor = [UIColor clearColor];//这两个颜色一定要是clearColor,不然删除到第一个时可能会看见输入的数字
    self.passwordField.tintColor = [UIColor clearColor];
    self.passwordField.layer.borderColor = [UIColor colorWithRed:222/255.0f green:222/255.0f blue:222/255.0f alpha:1].CGColor;
    self.passwordField.layer.borderWidth = 1;
    self.passwordField.layer.cornerRadius = 8.0;
    self.passwordField.keyboardType = UIKeyboardTypeNumberPad;
    self.passwordField.secureTextEntry = YES;
    [self.passwordField addTarget:self action:@selector(passwordFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
    self.passwordField.delegate = self;
    [self.passwordField becomeFirstResponder];
    [self addSubview:self.passwordField];
    
    
    //忘记密码
    self.forgetPassword = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [self.forgetPassword setTitle:@"忘记密码?" forState:UIControlStateNormal];
    self.forgetPassword.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
    [self.forgetPassword addTarget:self action:@selector(ForgetPassword) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:self.forgetPassword];
}

-(void) layoutSubviews {
    [super layoutSubviews];
    
    self.passwordField.frame = CGRectMake((ScreenWidth-ScreenWidth*0.15*6)/2, 70, ScreenWidth*0.15*6, ScreenWidth*0.15);
    
    [self.forgetPassword mas_makeConstraints:^(MASConstraintMaker *make) {
        make.right.equalTo(self.passwordField.mas_right);
        make.top.equalTo(self.passwordField.mas_bottom).with.offset(10);
        make.size.mas_equalTo(CGSizeMake(80, 16));
    }];
    
    //密码点要根据 passwordField.frame 来设置
    [self initDotsViews];
}

-(void) initDotsViews {
    //初始化数组
    self.passwordDotsArray = [NSMutableArray arrayWithCapacity:DotsNumber];
    
    CGFloat password_width = self.passwordField.frame.size.width/DotsNumber;
    CGFloat password_height = self.passwordField.frame.size.height;
    
    for (int i = 0; i < DotsNumber; i++) {
        
        //分割线
        UIView *line = [[UIView alloc] initWithFrame:CGRectMake(i * password_width, 0, 1, password_height)];
        line.backgroundColor = [UIColor colorWithRed:222/255.0f green:222/255.0f blue:222/255.0f alpha:1];
        //不要第一个分割线
        if(i!=0) {
            [self.passwordField addSubview:line];
        }

        //密码点x和y坐标
        CGFloat dotViewX = (i + 1)*password_width - password_width / 2.0 - DotWith_height / 2.0;
        CGFloat dotViewY = (password_height - DotWith_height) / 2.0;
        
        //密码点视图
         UIView *dotView = [[UIView alloc] initWithFrame:CGRectMake(dotViewX, dotViewY, DotWith_height, DotWith_height)];
        dotView.backgroundColor = [UIColor colorWithRed:30/255.0f green:30/255.0f blue:30/255.0f alpha:1];
        dotView.layer.cornerRadius = DotWith_height/2.0;
        
        //创建好之后先隐藏
        dotView.hidden = YES;
        
        [self.passwordField addSubview:dotView];
        [self.passwordDotsArray addObject:dotView];
    }
}

#pragma mark - 点击事件
-(void) TakeUpPassword {
    //收起视图
    [self.passwordField resignFirstResponder];
    //并清除密码
    [self cleanPassword];
    [UIView animateWithDuration:0.3 animations:^{
        self.frame = CGRectMake(ScreenWidth, ScreenHeight*0.34, ScreenWidth, ScreenHeight*0.66);
    }];
}

-(void) ForgetPassword {
    MZTLog(@"忘记密码");
}

#pragma mark - 判断密码
-(void)passwordFieldDidChange:(UITextField *)textField {
    //先隐藏全部密码点
    [self setDotsViewHidden];
    
    //再根据输入框的长度来设置显示的相应个数的密码点视图
    for (int i = 0; i < self.passwordField.text.length; i ++)
    {
        
        if (self.passwordDotsArray.count > i )
        {
            //取出密码点视图并显示
            UIView *dotView = self.passwordDotsArray[i];
            [dotView setHidden:NO];
        }
    }
    
    //当输入六位密码
    if (self.passwordField.text.length == 6)
    {
        //判断输入密码与用户密码相等
        if ([self.passwordField.text isEqualToString:self.password])
        {
            NSLog(@" 打印信息  密码正确");
            [textField resignFirstResponder];
            
            //显示等待付款动画
            [PaymentLoadingHUD showIn:self];
            self.PaymentText = [[UILabel alloc]init];
            self.PaymentText.text = @"正在付款...";
            self.PaymentText.font = [UIFont systemFontOfSize:14];
            CGSize size = [self.PaymentText.text sizeWithAttributes:@{NSFontAttributeName:self.PaymentText.font}];
            [self addSubview:self.PaymentText];
            [self.PaymentText mas_makeConstraints:^(MASConstraintMaker *make) {
                make.centerX.equalTo(self.mas_centerX).with.offset(10);
                make.centerY.equalTo(self.mas_centerY).with.offset(50);
                make.size.mas_equalTo(CGSizeMake(size.width+10, size.width));
            }];
            
            //显示付款成功动画
            NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(PaymentSuccess) userInfo:nil repeats:NO];
        }
        else
        {
            UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@""
                                                            message:@"支付密码不正确"
                                                           delegate:self
                                                  cancelButtonTitle:@"重新输入"
                                                  otherButtonTitles:@"忘记密码", nil];
            [alert show];
        }
    }
}

-(void) cleanPassword {
    ////清除密码
    self.passwordField.text = @"";//置空输入框
    [self setDotsViewHidden];//隐藏所有密码点视图
}

-(void) setDotsViewHidden {
    ////隐藏所有密码点
    for (UIView *view in self.passwordDotsArray) {
        [view setHidden:YES];
    }
}

-(void) PaymentSuccess {
    [PaymentLoadingHUD hideIn:self];
    [PaymentSuccessHUD showIn:self];
    self.PaymentText.text = @"付款成功";
}

#pragma mark - UITextFieldDelegate
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    
    // >= 六位数不能再输入
    if (self.passwordField.text.length >= DotsNumber) {
        return NO;
    }
    return YES;
}

#pragma mark - UIAlertViewDelegate
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    NSString* buttonTitle = [alertView buttonTitleAtIndex:buttonIndex];
    if ([buttonTitle isEqualToString:@"重新输入"]) {
        [self cleanPassword];
    }
    else if ([buttonTitle isEqualToString:@"忘记密码"]) {
        NSLog(@"忘记密码,重新设置密码");
    }
}

@end

 MZTTextField.h

#import <UIKit/UIKit.h>

@interface MZTTextField : UITextField

@end

MZTTextField.m

#import "MZTTextField.h"

@implementation MZTTextField


////禁止输入框的复制、粘贴、全选、剪切等操作
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    UIMenuController *MenuController = [UIMenuController sharedMenuController];
    if (MenuController) {
        [UIMenuController sharedMenuController].menuVisible = NO;
    }
    return NO;
}

@end

PaymentLoadingHUD.h

#import <UIKit/UIKit.h>

@interface PaymentLoadingHUD : UIView

-(void)start;

-(void)hide;

+(PaymentLoadingHUD*)showIn:(UIView*)view;

+(PaymentLoadingHUD*)hideIn:(UIView*)view;

@end

PaymentLoadingHUD.m

#import "PaymentLoadingHUD.h"

#define BlueColor [UIColor colorWithRed:28/255.0 green:138/255.0 blue:234/255.0 alpha:1]

static CGFloat lineWidth = 5.0f;

@implementation PaymentLoadingHUD
{
    CADisplayLink *link;
    CAShapeLayer *animationLayer;
    
    CGFloat startAngle;
    CGFloat endAngle;
    CGFloat progress;
}

-(instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
        [self buildUI];
    }
    return self;
}

-(void) buildUI {
    animationLayer = [CAShapeLayer layer];
    animationLayer.bounds = CGRectMake(0, 0, 60, 60);
    animationLayer.position = CGPointMake(self.bounds.size.width/2.0f, self.bounds.size.height/2.0);
    animationLayer.fillColor = [UIColor clearColor].CGColor;
    animationLayer.strokeColor = BlueColor.CGColor;
    animationLayer.lineWidth = lineWidth;
    animationLayer.lineCap = kCALineCapRound;
    
    [self.layer addSublayer:animationLayer];
    
    
    link = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkAction)];
    [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    link.paused = true;
}

-(void)displayLinkAction {
    progress += [self speed];
    if (progress >= 1) {
        progress = 0;
    }
    [self updateAnimationLayer];
}

-(void)updateAnimationLayer{
    startAngle = -M_PI_2;
    endAngle = -M_PI_2 +progress * M_PI * 2;
    if (endAngle > M_PI) {
        CGFloat progress1 = 1 - (1 - progress)/0.25;
        startAngle = -M_PI_2 + progress1 * M_PI * 2;
    }
    CGFloat radius = animationLayer.bounds.size.width/2.0f - lineWidth/2.0f;
    CGFloat centerX = animationLayer.bounds.size.width/2.0f;
    CGFloat centerY = animationLayer.bounds.size.height/2.0f;
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(centerX, centerY) radius:radius startAngle:startAngle endAngle:endAngle clockwise:true];
    path.lineCapStyle = kCGLineCapRound;
    
    animationLayer.path = path.CGPath;
}

-(CGFloat)speed{
    if (endAngle > M_PI) {
        return 0.3/60.0f;
    }
    return 2/60.0f;
}

+(PaymentLoadingHUD *)showIn:(UIView*)view {
    [self hideIn:view];
    PaymentLoadingHUD *hud = [[PaymentLoadingHUD alloc] initWithFrame:view.bounds];
    [hud start];
    [view addSubview:hud];
    return hud;
}

+(PaymentLoadingHUD *)hideIn:(UIView *)view {
    PaymentLoadingHUD *hud = nil;
    for (PaymentLoadingHUD *subView in view.subviews) {
        if ([subView isKindOfClass:[PaymentLoadingHUD class]]) {
            [subView hide];
            [subView removeFromSuperview];
            hud = subView;
        }
    }
    return hud;
}

-(void)start {
    link.paused = false;
}

-(void)hide {
    link.paused = true;
    progress = 0;
}
@end

PaymentSuccessHUD.h

#import <UIKit/UIKit.h>

@interface PaymentSuccessHUD : UIView<CAAnimationDelegate>

-(void)start;

-(void)hide;

+(PaymentSuccessHUD*)showIn:(UIView*)view;

+(PaymentSuccessHUD*)hideIn:(UIView*)view;

@end

PaymentSuccessHUD.m

#import "PaymentSuccessHUD.h"

static CGFloat lineWidth = 4.0f;
static CGFloat circleDuriation = 0.5f;
static CGFloat checkDuration = 0.2f;

#define BlueColor [UIColor colorWithRed:28/255.0 green:138/255.0 blue:234/255.0 alpha:1]

@implementation PaymentSuccessHUD
{
     CALayer *_animationLayer;
}

//显示
+ (PaymentSuccessHUD*)showIn:(UIView*)view {
    [self hideIn:view];
    PaymentSuccessHUD *hud = [[PaymentSuccessHUD alloc] initWithFrame:view.bounds];
    [hud start];
    [view addSubview:hud];
    return hud;
}

//隐藏
+ (PaymentSuccessHUD *)hideIn:(UIView *)view {
    PaymentSuccessHUD *hud = nil;
    for (PaymentSuccessHUD *subView in view.subviews) {
        if ([subView isKindOfClass:[PaymentSuccessHUD class]]) {
            [subView hide];
            [subView removeFromSuperview];
            hud = subView;
        }
    }
    return hud;
}

- (void)start {
    [self circleAnimation];
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 0.8 * circleDuriation * NSEC_PER_SEC);
    dispatch_after(time, dispatch_get_main_queue(), ^(void){
        [self checkAnimation];
    });
}

- (void)hide {
    for (CALayer *layer in _animationLayer.sublayers) {
        [layer removeAllAnimations];
    }
}

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self buildUI];
    }
    return self;
}

- (void)buildUI {
    _animationLayer = [CALayer layer];
    _animationLayer.bounds = CGRectMake(0, 0, 60, 60);
    _animationLayer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
    [self.layer addSublayer:_animationLayer];
}

//画圆
- (void)circleAnimation {
    
    CAShapeLayer *circleLayer = [CAShapeLayer layer];
    circleLayer.frame = _animationLayer.bounds;
    [_animationLayer addSublayer:circleLayer];
    circleLayer.fillColor =  [[UIColor clearColor] CGColor];
    circleLayer.strokeColor  = BlueColor.CGColor;
    circleLayer.lineWidth = lineWidth;
    circleLayer.lineCap = kCALineCapRound;
    
    
    CGFloat lineWidth = 5.0f;
    CGFloat radius = _animationLayer.bounds.size.width/2.0f - lineWidth/2.0f;
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:circleLayer.position radius:radius startAngle:-M_PI/2 endAngle:M_PI*3/2 clockwise:true];
    circleLayer.path = path.CGPath;
    
    CABasicAnimation *circleAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    circleAnimation.duration = circleDuriation;
    circleAnimation.fromValue = @(0.0f);
    circleAnimation.toValue = @(1.0f);
    circleAnimation.delegate = self;
    [circleAnimation setValue:@"circleAnimation" forKey:@"animationName"];
    [circleLayer addAnimation:circleAnimation forKey:nil];
}

//对号
- (void)checkAnimation {
    
    CGFloat a = _animationLayer.bounds.size.width;
    
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(a*2.7/10,a*5.4/10)];
    [path addLineToPoint:CGPointMake(a*4.5/10,a*7/10)];
    [path addLineToPoint:CGPointMake(a*7.8/10,a*3.8/10)];
    
    CAShapeLayer *checkLayer = [CAShapeLayer layer];
    checkLayer.path = path.CGPath;
    checkLayer.fillColor = [UIColor clearColor].CGColor;
    checkLayer.strokeColor = BlueColor.CGColor;
    checkLayer.lineWidth = lineWidth;
    checkLayer.lineCap = kCALineCapRound;
    checkLayer.lineJoin = kCALineJoinRound;
    [_animationLayer addSublayer:checkLayer];
    
    CABasicAnimation *checkAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    checkAnimation.duration = checkDuration;
    checkAnimation.fromValue = @(0.0f);
    checkAnimation.toValue = @(1.0f);
    checkAnimation.delegate = self;
    [checkAnimation setValue:@"checkAnimation" forKey:@"animationName"];
    [checkLayer addAnimation:checkAnimation forKey:nil];
}

@end

猜你喜欢

转载自blog.csdn.net/qq_36557133/article/details/82702754