iOS仿支付宝车牌号码输入键盘

来源:互联网 发布:淘宝刷好评买家封号 编辑:程序博客网 时间:2024/04/19 23:09

点击上方“iOS开发”,选择“置顶公众号”

关键时刻,第一时间送达!


最近由于项目需求,需要录入车牌号码,诸多限制条件要判断车牌号码的合理性,最后看见支付宝的车牌号码输入键盘,决定自己写一个


考虑过用textfield的inputview来替换,但是本人总感觉会有坑在里面,所以最后决定用自定义的view来做一个 只要做一个简单的弹出动画即可实现inpuview一样的效果,创建文件都会的 我就直接上代码了


#import <UIKit/UIKit.h>

//键盘view的代理,用来监控键盘输入

@protocol LYPlateKeyBoardViewDelegate <NSObject>

//点击键盘上的按钮

- (void)clickWithString:(NSString *)string;

//点击删除按钮

- (void)deleteBtnClick;

@end

@interface LYPlateKeyBoardView : UIView

@property (nonatomic, weak) id<LYPlateKeyBoardViewDelegate> delegate;

//公共方法 - 字符串已经删除完毕

- (void)deleteEnd;

@end


在这里用的代理方法相信大家都会看懂,我就不用多做解释了


.m 文件


#define kWidth  self.frame.size.width

#define kHeight self.frame.size.height

#define HEXCOLOR(hex, alp) [UIColor colorWithRed:((float)((hex & 0xFF0000) >> 16)) / 255.0 green:((float)((hex & 0xFF00) >> 8)) / 255.0 blue:((float)(hex & 0xFF)) / 255.0 alpha:alp]

#import "LYPlateKeyBoardView.h"

@interface LYPlateKeyBoardView()<UIGestureRecognizerDelegate>

{

    UIView *_backView1; //第一个view

    UIView *_backView2; //第二个view

//    UIView *_bottomView;

    UIButton *_btn;

}

@property (nonatomic, strong) NSArray *array1; //省市简写数组

@property (nonatomic, strong) NSArray *array2; //车牌号码字母数字数组

@end


构思时想用一个view来切换数组的方式来切换显示的不同内容,发现两个数组以及view上布局有点让人头疼,就用了2个view来布局,只要根据输入的字符来隐藏其中一个view


@implementation LYPlateKeyBoardView

- (NSArray *)array1 {

    if (!_array1) {

        _array1 = @[@"京",@"津",@"渝",@"沪",@"冀",@"晋",@"辽",@"吉",@"黑",@"苏",@"浙",@"皖",@"闽",@"赣",@"鲁",@"豫",@"鄂",@"湘",@"粤",@"琼",@"川",@"贵",@"云",@"陕",@"甘",@"青",@"蒙",@"桂",@"宁",@"新",@"",@"藏",@"使",@"领",@"警",@"学",@"港",@"澳",@""];

    }

    return _array1;

}

- (NSArray *)array2 {

    if (!_array2) {

        _array2 = @[@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"0",@"Q",@"W",@"E",@"R",@"T",@"Y",@"U",@"I",@"O",@"P",@"A",@"S",@"D",@"F",@"G",@"H",@"J",@"K",@"L",@"",@"Z",@"X",@"C",@"V",@"B",@"N",@"M",@""];

    }

    return _array2;

}


这里先懒加载两个数组,下面就是view的初始化方法,在初始化方法中注册了一个通知和添加一个手势,用途代码注释上都有些


- (instancetype)initWithFrame:(CGRect)frame {

    

    if (self = [super initWithFrame:frame]) {

        

        self.backgroundColor = HEXCOLOR(0x000000, 0.1);

        

        //注册一个通知,后面会用到,来监听abc字母键

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFAction:) name:@"abc" object:nil];

        

        //添加一个手势,点击键盘外面收回键盘

        UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hiddenView)];

        recognizer.delegate = self;

        [self addGestureRecognizer:recognizer];

        

        [self setupUI];

    }

    return self;

}


具体布局在 [self setupUI] 这个方法里面,我就偷懒了没有在layoutsubview方法里面实现,代码有点繁琐,主要就是计算坐标,九宫格布局,这个可以自己写的,相信都会的,废话不多说,请看代码:


- (void)setupUI {

    

    CGSize size = [UIScreen mainScreen].bounds.size;

    _backView1 = [[UIView alloc] initWithFrame:CGRectMake(0, size.height, size.width, size.height * 0.33)];

    _backView1.backgroundColor = HEXCOLOR(0xd2d5da, 1);

    _backView1.hidden = NO;

    

    _backView2 = [[UIView alloc] initWithFrame:CGRectMake(0, size.height, size.width, size.height * 0.33)];

    _backView2.hidden = YES;

    _backView2.backgroundColor = HEXCOLOR(0xd2d5da, 1);

    

    [self addSubview:_backView1];

    [self addSubview:_backView2];

    

    int row = 4;

    int column = 10;

    CGFloat btnY = 4;

    CGFloat btnX = 2;

    CGFloat maginR = 5;

    CGFloat maginC = 10;

    CGFloat btnW = (size.width - maginR * (column -1) - 2 * btnX)/column;

    CGFloat btnH = (_backView1.frame.size.height - maginC * (row - 1) - 6) / row;

    CGFloat m = 12;

    CGFloat w = (size.width - 24 - 7 * btnW - 6 * maginR - 2 * btnX)/2;

    CGFloat mw = (size.width - 8 * maginR - 9 * btnW - 2 * btnX) / 2;

    NSLog(@"LY >> count - %zd", self.array1.count);

    for (int i = 0; i < self.array1.count; i++) {

        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];

        

        if (i / column == 3) {

            if (i == 30) {

                 btn.frame = CGRectMake(btnX, btnY + 3 * (btnH + maginC), w, btnH);

                [btn setBackgroundImage:[UIImage imageNamed:@"key_abc"] forState:UIControlStateNormal];

                btn.enabled = NO;

                _btn = btn;

            }else if (i == 38) {

                btn.frame = CGRectMake(6 * (btnW + maginR) + btnW + w + m + m, btnY + 3 * (btnH + maginC), w, btnH);

                [btn setBackgroundImage:[UIImage imageNamed:@"key_over"] forState:UIControlStateNormal];

            }else {

                btn.frame = CGRectMake((i % column - 1)*(btnW + maginR) + w + m + btnX, btnY + 3 * (btnH + maginC), btnW, btnH);

                [btn setBackgroundImage:[UIImage imageNamed:@"key_number"] forState:UIControlStateNormal];

            }

        }else {

            btn.frame = CGRectMake(btnW * (i % column) + i % column * maginR + btnX, btnY + i/column * (btnH + maginC), btnW, btnH);

            [btn setBackgroundImage:[UIImage imageNamed:@"key_number"] forState:UIControlStateNormal];

        }

        [btn setTitleColor:HEXCOLOR(0x23262F, 1) forState:UIControlStateNormal];

        [btn setTitle:self.array1[i] forState:UIControlStateNormal];

        btn.layer.cornerRadius = 3;

        btn.layer.masksToBounds = YES;

        btn.tag = i;

        [btn addTarget:self action:@selector(btn1Click:) forControlEvents:UIControlEventTouchUpInside];

        [_backView1 addSubview:btn];

    }

    

    for (int i = 0; i < self.array2.count; i++) {

        

        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];

        

        if (i >= 20 && i < 29) {

            

            btn.frame = CGRectMake(btnX + mw + (btnW + maginR) * (i % column), btnY + 2 * (btnH + maginC), btnW, btnH);

            [btn setBackgroundImage:[UIImage imageNamed:@"key_number"] forState:UIControlStateNormal];

            

        }else if (i >= 29) {

            if (i == 29) {

                btn.frame = CGRectMake(btnX, btnY + 3 * (btnH + maginC), w, btnH);

                [btn setBackgroundImage:[UIImage imageNamed:@"key_back"] forState:UIControlStateNormal];

            }else if (i == 37) {

                btn.frame = CGRectMake(6 * (btnW + maginR) + btnW + w + m + m + btnX, btnY + 3 * (btnH + maginC), w, btnH);

                [btn setBackgroundImage:[UIImage imageNamed:@"key_over"] forState:UIControlStateNormal];

            }else {

                btn.frame = CGRectMake((i % column)*(btnW + maginR) + w + m + btnX, btnY + 3 * (btnH + maginC), btnW, btnH);

                [btn setBackgroundImage:[UIImage imageNamed:@"key_number"] forState:UIControlStateNormal];

            }

        }else {

            btn.frame = CGRectMake(btnW * (i % column) + i % column * maginR + btnX, btnY + i/column * (btnH + maginC), btnW, btnH);

            [btn setBackgroundImage:[UIImage imageNamed:@"key_number"] forState:UIControlStateNormal];

        }

        [btn setTitleColor:HEXCOLOR(0x23262F, 1) forState:UIControlStateNormal];

        [btn setTitle:self.array2[i] forState:UIControlStateNormal];

        

        btn.layer.cornerRadius = 3;

        btn.layer.masksToBounds = YES;

        btn.tag = i;

        [btn addTarget:self action:@selector(btn2Click:) forControlEvents:UIControlEventTouchUpInside];

        [_backView2 addSubview:btn];

    }

    

    [UIView animateWithDuration:0.3 animations:^{

        CGRect frame = _backView1.frame;

        frame.origin.y = size.height - size.height * 0.33;

        _backView1.frame = frame;

    }];

    

    [UIView animateWithDuration:0.3 animations:^{

        CGRect frame = _backView2.frame;

        frame.origin.y = size.height - size.height * 0.33;

        _backView2.frame = frame;

    }];

}


这段代码我没有做注释,就是九宫格布局,计算坐标,写过九宫格的都会,我就不多做解释了,关键在于后面逻辑的实现,下面是键盘上按钮的点击事件的监听代码:


- (void)btn1Click:(UIButton *)sender {

    

    NSLog(@"LY >>> array1: - %@ -- tag - %zd", self.array1[sender.tag],sender.tag);

    _btn.enabled = YES;

    if (sender.tag == 30) {

        NSLog(@"点击了abc键");

        if (_backView2.hidden) {

            NSLog(@"_backView2 隐藏了");

            _backView1.hidden = YES;

            _backView2.hidden = NO;

        }else {

           sender.enabled = NO;

        }

        

    }else if (sender.tag == 38){

        NSLog(@"点击了删除键");

        if (_backView2.hidden) {

            if (self.delegate && [self.delegate respondsToSelector:@selector(deleteBtnClick)]) {

                [self.delegate deleteBtnClick];

            }

        }

    }else {

        _backView1.hidden = YES;

        _backView2.hidden = NO;

        

        if (self.delegate && [self.delegate respondsToSelector:@selector(clickWithString:)]) {

            [self.delegate clickWithString:self.array1[sender.tag]];

        }

    }

}


- (void)btn2Click:(UIButton *)sender {

    

    NSLog(@"LY >>> array2: - %@ -- tag - %zd", self.array2[sender.tag], sender.tag);

    if (sender.tag == 29) {

        NSLog(@"点击了abc键");

        _backView1.hidden = NO;

        _backView2.hidden = YES;

        

    }else if (sender.tag == 37) {

        NSLog(@"点击了删除键");

        if (self.delegate && [self.delegate respondsToSelector:@selector(deleteBtnClick)]) {

            [self.delegate deleteBtnClick];

        }

        

    }else {

        if (self.delegate && [self.delegate respondsToSelector:@selector(clickWithString:)]) {

            [self.delegate clickWithString:self.array2[sender.tag]];

        }

    }

}


btn1的点击事件方法谁backview1上按钮的点击事件

btn2的点击事件方法是backview2上按钮的点击事件

分属于不同的view,这样谁都不会影响到谁,哈哈


剩下的代码我就一次性贴上去了,不多解释了,上面有注释,应该不难懂的


- (void)deleteEnd {

    _backView1.hidden = NO;

    _backView2.hidden = YES;

}


//通知的监听方法

- (void)textFAction:(NSNotification *)notification {

    

    NSLog(@"LY >> info -- %@", notification.userInfo);

    NSString *str = notification.userInfo[@"text"];

    if (str.length == 0) {

        _btn.enabled = NO;

    }else if (str.length == 7) {

        [self hiddenView];

    }else {

        _backView1.hidden = YES;

        _backView2.hidden = NO;

       _btn.enabled = YES;

    }

}


//初次弹出键盘时

- (void)showWithString:(NSString *)string {

    NSLog(@"LY >> string -- %@", string);

    

    _backView1.hidden = YES;

    _backView2.hidden = NO;

    _btn.enabled = YES;

}


//收回键盘

- (void)hiddenView {

    

    CGSize size = [UIScreen mainScreen].bounds.size;

    

    [UIView animateWithDuration:0.3 animations:^{

        CGRect frame = _backView1.frame;

        frame.origin.y = size.height;

        _backView1.frame = frame;

    } completion:^(BOOL finished) {

        [self removeFromSuperview];

    }];

    

    [UIView animateWithDuration:0.3 animations:^{

        CGRect frame = _backView2.frame;

        frame.origin.y = size.height;

        _backView2.frame = frame;

    } completion:^(BOOL finished) {

        [self removeFromSuperview];

    }];

}


//手势的代理方法

#pragma mark >> UIGestureRecognizerDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {

    if ([touch.view isDescendantOfView:_backView1] ||

        [touch.view isDescendantOfView:_backView2] ) {

        

        return NO;

    }

    return YES;

}


//  颜色转换为背景图片

//  这个之前用,后来让美工做了几张图片,一共就需要4张图片(abc建背景图,删除键 返回键 字符键)

- (UIImage *)imageWithColor:(UIColor *)color {

    

    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);

    UIGraphicsBeginImageContext(rect.size);

    CGContextRef context = UIGraphicsGetCurrentContext();

    

    CGContextSetFillColorWithColor(context, [color CGColor]);

    CGContextFillRect(context, rect);

    

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    

    return image;

}


//销毁通知

- (void)dealloc {

    

    [[NSNotificationCenter defaultCenter] removeObserver:self];

}


--------------------------以上是自定义view的代码------------------------------


以上就是自定义键盘view的所有代码,按次序拷贝下去,什么都不用改,就可以用

下面重点来了,如何用这个键盘了,怎么实现逻辑了,相信做过的人脑袋里就会想分属不同的类,调用 监听等等 ,我就不废话了,下面上代码:


我申明下,为了避免textfield点击会弹出键盘这种情况发生,我用的是一个textfield上放一个和textfield一样大小的button,当然button肯定不是textfield的子view,具体布局就是一个view上先放了一个textfield 在放一个button盖在上面,这样textfield的监听方法以及代理都接收不到信号,因为上面盖的有一个button。点击button弹出键盘,这个不难的。拖线更简单


@implementation ViewController


@property (weak, nonatomic) IBOutlet UITextField *plateTF;

@property (nonatomic, strong) LYPlateKeyBoardView *keyboardView;


在要弹出键盘的类中添加一个属性,后面要用到,当然如果不用也可以不用添加的,直接写成局部的就可以


- (void)viewDidLoad {

    [super viewDidLoad];

    

    [self.plateTF addObserver:self forKeyPath:@"text" options:NSKeyValueObservingOptionNew  context:nil];

}


在这个方法中要做一件事,注册观察者,也就是kvc,为什么要用观察者,上面申明说了,textfield 上面盖了一个button,上面解释过了,这里就不解释了。当然不一定要在个方法里面,你觉得合适就行,如果你封装好的方法里面,,load的时候会调用这个方法。


kvc实现的方法


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {

    

    NSLog(@"LY >>>>>  text --- %@", change[@"new"]);

    NSLog(@"LY >>>>>  self.plateTF.text --- %@", self.plateTF.text);

    

   //判断车牌号码大于7位的时候,怎么输入就输不进去了

   if (self.carNumTF.text.length > 7) {


        NSString *str = [self.plateTF.text substringToIndex:self.plateTF.text.length - 1];

        NSLog(@"LY >>> str --- %@", str);

        self.plateTF.text = str;

    }

    //发送通知并把textfield的值传过去

    [[NSNotificationCenter defaultCenter] postNotificationName:@"abc" object:nil userInfo:@{@"text": change[@"new"]}];

    

}


通知的原理大家都知道,键盘view里有实现方法,可以一一对应过去

下面是弹出键盘的方法,就是点击textfield上的button的点击事件


- (IBAction)btnClick:(id)sender {

    

    self.keyboardView = [[LYPlateKeyBoardView alloc] initWithFrame:[UIScreen mainScreen].bounds];

    self.keyboardView.delegate = self;

    [self.view addSubview:self.keyboardView];


//先判断下textfield上有没有之前输入的车牌号码,主要是来初始化view用的,结合键盘view的代码看下,很容易懂的

if (self.plateTF.text.length > 0) {

        [self.keyboardView showWithString:self.plateTF.text];

    }

    

}


这里说明下,因为我是没有加导航栏的view,所以键盘的告诉是没有问题的,可以如果一旦加了导航栏,那么这里添加键盘的时候应该用:


[self.view.window addSubview:self.keyboardView];


下面就是键盘view的代理方法实现


#pragma mark >> LYPlateKeyBoardViewDelegate

- (void)clickWithString:(NSString *)string {

    

    NSLog(@"carNumTF -- %@", self.plateTF.text);

    

    //输入一个字符拼接到后面

    self.plateTF.text = [self.plateTF.text stringByAppendingString:string];

}


- (void)deleteBtnClick {

    

     //这里要多个判断,不然会崩的,一直点击删除键的情况下

    if (self.carNumTF.text.length == 0) {

        

        

    }else if (self.plateTF.text.length == 1) {

        //删除完了,没有字符可以删除了,切换显示的view

        [self.keyboardView deleteEnd];

        self.plateTF.text = [self.plateTF.text substringToIndex:[self.plateTF.text length] - 1];

    }else {

        self.plateTF.text = [self.plateTF.text substringToIndex:[self.plateTF.text length] - 1];

    }

}


在此基本告于段落,不过有的人可能会用在项目中的时候就崩掉了,相信一些大神肯定知道问题出在哪里,也就是最后一步,也是很重要的一步,销毁观察者,这个不能忘记了,否则用到项目中会崩的。


- (void)dealloc {

    

    //添加观察者之后 监听完毕之后要删除观察者

    [self.plateTF removeObserver:self forKeyPath:@"text"];

}


效果图如下:


WechatIMG44.png



WechatIMG45.png



keyboard.gif


最后的最后,本人是一个ios小菜鸟,代码写的不好,请大神们不要见怪,谢谢!



  • 来自:琅琊玥

  • 链接:http://www.jianshu.com/p/98ca11e9c453

  • iOS开发整理发布,转载请联系作者授权

【点击成为Java大神】

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 公司诈骗离职人怎么办 支付宝重复扣款怎么办 微信重复付款怎么办 花呗重复扣款怎么办 淘宝不退款怎么办投诉 淘宝怎么办极速退货 淘宝换货没收到怎么办 淘宝卖货让人换货了怎么办 淘宝换货关闭了怎么办 物流透露客户信息怎么办 淘宝信息泄漏后怎么办 淘宝信息泄漏了怎么办 天猫贷款还不上怎么办 车贷下不来定金怎么办 建行车贷不通过怎么办 天猫介入失败怎么办 天猫投诉没用怎么办 天猫被投诉商标侵权怎么办 虚假发货有天猫红包怎么办 淘宝代购是假货怎么办 闲鱼对方不在怎么办 小米商城退款慢怎么办 小米手机第三方拿货是怎么办 oppo手机卡被锁怎么办 下巴粉刺特别多怎么办 苹果6sp手机卡怎么办 苹果手机无服务怎么办 京东买电脑没发票怎么办 买东西发票丢了怎么办 在天猫上买了假货怎么办 苹果发票丢了怎么办 iphone8屏幕摔了怎么办 在手机店买到翻新机怎么办 信用卡网上买东西退款怎么办 在唯品会买到假的护肤品怎么办 天猫买东西发票怎么办 支付宝无法收款怎么办 买到苹果假货怎么办 16周岁怎么办手机分期 淘宝打假扣分了怎么办 买到不合格食品怎么办