自定义身份证键盘,iOS7+

身份证组成

根据《中华人民共和国国家标准GB 11643-1999》中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。顺序码的奇数分给男性,偶数分给女性。校验码是根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2校验码计算出来的检验码。

  • 前1、2位数字表示:所在省(直辖市、自治区)的代码;
  • 第3、4位数字表示:所在地级市(自治州)的代码;
  • 第5、6位数字表示:所在区(县、自治县、县级市)的代码;
  • 第7—14位数字表示:出生年、月、日;
  • 第15、16位数字表示:所在地的派出所的代码;
  • 第17位数字表示性别:奇数表示男性,偶数表示女性;
  • 第18位数字是校检码:也有的说是个人信息码,不是随计算机的随机产生,它是 用来检验身份证的正确性。校检码可以是0—9的数字,有时也用x表示。作为尾号的校验码,是由号码编制单位按统一的公式计算出来的,如果某人的尾号是0-9,都不会出现X,但如果尾号是10,那么就得用X来代替,因为如果用10做尾号,那么此人的身份证就变成了19位。X是罗马数字的10,用X来代替10,可以保证公民的身份证符合国家标准。

需求

很多情况下,应用都需要用户输入身份证号。身份证号的组成很简单,15位身份证全部由数字组成,18位身份证由数字加X字母组合而成,所以这里只需要关心18位身份证。在用户输入身份证号时,为了有更好的体验,我们都会限制UITextFieldkeyboardType。但是有的身份证号中有X,在现有keyboardType中没有一个是完全满足需求的。在这种情况下,我们只能自定义一个身份证键盘,一个只包含数字和一个X字母的键盘。

实现方式

自定义方式有两种

  • 自己完全重新绘制一个键盘View,0~9十个数字按钮,一个X按钮,一个删除按钮,最后直接将自定义的控件赋值给UITextFieldinputView
  • UITextFieldkeyboardType设置为UIKeyboardTypeNumberPad,然后再此基础上上添加一个X按钮,并监听X按钮的点击。

代码

方式一:完全自定义

优点:完全自定义,自己控制起来比较方便,而且不会被监听到,比较安全;不同UITextField之间切换也比较自然;适用所有设备和系统版本
缺点:要完全定义,所有的控制逻辑要自己写,不过也不是很复杂

自定义身份证键盘,iOS7+_第1张图片
image.png

IDKeyboardView.h

#import 

@protocol IDKeyboardViewDelegate;

@interface IDKeyboardView : UIView

@property (nonatomic, weak) id delegate;

@end
//代理
@protocol IDKeyboardViewDelegate 
@optional
//点击0~9和X时调用
- (void)didKeyboardItemSelected:(NSString *)item;
//点击删除时调用
- (void)didKeyboardDeletedClicked;

@end

IDKeyboardView.m

#import "IDKeyboardView.h"

@implementation IDKeyboardView
{
    NSMutableArray *_buttons;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        self.backgroundColor = [UIColor blackColor];
        NSArray *items = @[@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"X",@"0",@"删除"];
        _buttons = [NSMutableArray array];
        for (NSInteger i = 0; i < items.count; i++)
        {
            UIButton *button = [[UIButton alloc]init];
            button.tag = i;
            [button setTitle:items[i] forState:UIControlStateNormal];
            [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
            if (i < 11)  button.titleLabel.font = [UIFont systemFontOfSize:27];
            if (i == 9 || i == 11)
            {
                //生成纯色的背景图片imageWithColor和colorWithHexString都是YYKit中的方法
                [button setBackgroundImage:[UIImage imageWithColor:[UIColor colorWithHexString:@"#D1D5DA"]] forState:UIControlStateNormal];
                [button setBackgroundImage:[UIImage imageWithColor:[UIColor whiteColor]] forState:UIControlStateHighlighted];
            }else
            {
                [button setBackgroundImage:[UIImage imageWithColor:[UIColor whiteColor]] forState:UIControlStateNormal];
                [button setBackgroundImage:[UIImage imageWithColor:[UIColor colorWithHexString:@"#D1D5DA"]] forState:UIControlStateHighlighted];
            }
            [button addTarget:self action:@selector(didItemClicked:) forControlEvents:UIControlEventTouchUpInside];
            [self addSubview:button];
            [_buttons addObject:button];
        }
    }
    return self;
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    CGFloat width = (self.frame.size.width - 1) / 3;
    CGFloat height = (self.frame.size.height - 1.5) / 4;
    for (NSInteger i = 0; i < _buttons.count; i++)
    {
        UIButton *button = _buttons[i];
        button.frame = CGRectMake((width + 0.5) * (i % 3), (height + 0.5) * (i / 3), width, height);
    }
}

- (void)didItemClicked:(UIButton *)sender
{
    if (_delegate)
    {
        if (sender.tag == 11 && [_delegate respondsToSelector:@selector(didKeyboardDeletedClicked)])
            [_delegate didKeyboardDeletedClicked];
        else if([_delegate respondsToSelector:@selector(didKeyboardItemSelected:)])
            [_delegate didKeyboardItemSelected:[sender titleForState:UIControlStateNormal]];
    }
}

@end

ViewController

#define SCREEN_SIZE         [UIApplication sharedApplication].keyWindow.frame.size

CGFloat width = SCREEN_SIZE.width;
CGFloat height = SCREEN_SIZE.width / 320 * 216;
if (height > 300) height = 300;//计算一个合适的高度
/*
 *  初始化IDKeyboardView
 *  设置代理
 *  将keyboardView赋值给UITextField的inputView
 */
IDKeyboardView *keyboardView = [[IDKeyboardView alloc]initWithFrame:CGRectMake(0, 0, width, height)];
keyboardView.delegate = self;
idCardField.inputView = keyboardView;

/*
 *  实现相应代理
 */
#pragma mark - IDKeyboardViewDelegate
- (void)didKeyboardDeletedClicked
{
    [idCardField deleteBackward];
}

- (void)didKeyboardItemSelected:(NSString *)item
{
    if ([item isEqualToString:@"X"] && [idCardField.text containsString:@"X"]) return;
    [idCardField replaceRange:idCardField.selectedTextRange withText:item];
}

方式二:设置keyboardTypeUIKeyboardTypeNumberPad,添加X按钮

优点:不需要完全自定义,只需要添加一个按钮就可以;只需要控制好X按钮的显示和隐藏就可以了
缺点:代码相对来说有点多o(╯□╰)o,而且不适合iPad

自定义身份证键盘,iOS7+_第2张图片
image.png
#import 

@interface KeyboardVC ()

@property (nonatomic, strong) UIButton *xButton;
@property (nonatomic, strong) UITextField *idField;

@end

@implementation KeyboardVC

- (void)viewDidLoad
{
    [super viewDidLoad];
    //初始化UITextField
    //为UITextField设置代理
    //添加UITextField到self.view上
    //self.view可能会添加多个UITextField
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    //需要监听键盘
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (UIButton *)xButton
{
    if (!_xButton)
    {
       _xButton = [[UIButton alloc]init];
       _xButton.alpha = 0;//alpha设置为0是为了动画效果
       _xButton.titleLabel.font = [UIFont systemFontOfSize:27];
       [_xButton setTitle:@"X" forState:(UIControlStateNormal)];
       [_xButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
       [_xButton setBackgroundImage:[UIImage imageWithColor:[UIColor whiteColor]] forState:UIControlStateHighlighted];
       [_xButton addTarget:self action:@selector(didXClicked:) forControlEvents:UIControlEventTouchUpInside];
    }
    return _xButton;
}

//点击X按钮
- (void)didXClicked:(UIButton *)sender
{
    [_idField replaceRange:_idField.selectedTextRange withText:@"X"];
}

//获取系统版本号,方法来YYKit
- (CGFloat)_systemVersion
{
    static CGFloat v;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        v = [UIDevice currentDevice].systemVersion.floatValue;
    });
    return v;
}

//获取当前的FirstResponder View,方法来自TPKeyboardAvoiding
- (UIView*)findFirstResponderView:(UIView *)view
{
    for (UIView *childView in view.subviews)
    {
        if ([childView respondsToSelector:@selector(isFirstResponder)] && [childView isFirstResponder] ) return childView;
        UIView *result = [self findFirstResponderView];
        if ( result ) return result;
    }
    return nil;
}

//获取KeyboardView,方法来YYKit
- (UIView *)_getKeyboardViewFromWindow:(UIWindow *)window
 {
    /*
     iOS 6/7:
     UITextEffectsWindow
        UIPeripheralHostView << keyboard
     
     iOS 8:
     UITextEffectsWindow
        UIInputSetContainerView
            UIInputSetHostView << keyboard
     
     iOS 9:
     UIRemoteKeyboardWindow
        UIInputSetContainerView
            UIInputSetHostView << keyboard
     */
    if (!window) return nil;
    
    // Get the window
    NSString *windowName = NSStringFromClass(window.class);
    if ([self _systemVersion] < 9)
    {  // UITextEffectsWindow
        if (windowName.length != 19) return nil;
        if (![windowName hasPrefix:@"UI"]) return nil;
        if (![windowName hasSuffix:@"TextEffectsWindow"]) return nil;
    } else 
    {   // UIRemoteKeyboardWindow
        if (windowName.length != 22) return nil;
        if (![windowName hasPrefix:@"UI"]) return nil;
        if (![windowName hasSuffix:@"RemoteKeyboardWindow"]) return nil;
    }
    
    // Get the view
    if ([self _systemVersion] < 8)
    {
        // UIPeripheralHostView
        for (UIView *view in window.subviews)
        {
            NSString *viewName = NSStringFromClass(view.class);
            if (viewName.length != 20) continue;
            if (![viewName hasPrefix:@"UI"]) continue;
            if (![viewName hasSuffix:@"PeripheralHostView"]) continue;
            return view;
        }
    } else 
    {   // UIInputSetContainerView
        for (UIView *view in window.subviews)
        {
            NSString *viewName = NSStringFromClass(view.class);
            if (viewName.length != 23) continue;
            if (![viewName hasPrefix:@"UI"]) continue;
            if (![viewName hasSuffix:@"InputSetContainerView"]) continue;
            // UIInputSetHostView
            for (UIView *subView in view.subviews)
            {
                NSString *subViewName = NSStringFromClass(subView.class);
                if (subViewName.length != 18) continue;
                if (![subViewName hasPrefix:@"UI"]) continue;
                if (![subViewName hasSuffix:@"InputSetHostView"]) continue;
                return subView;
            }
        }
    }
    
    return nil;
}

//获取keyboardView,方法来YYKit
- (UIView *)keyboardView
 {
    UIApplication *app = [UIApplication sharedApplication];
    if (!app) return nil;
    
    UIWindow *window = nil;
    UIView *view = nil;
    for (window in app.windows)
    {
        view = [self _getKeyboardViewFromWindow:window];
        if (view) return view;
    }
    window = app.keyWindow;
    view = [self _getKeyboardViewFromWindow:window];
    if (view) return view;
    return nil;
}

//获取KeyboardView所在的Window,方法来YYKit
- (UIWindow *)keyboardWindow 
{
    UIApplication *app = [UIApplication sharedApplication];
    if (!app) return nil;
 
    UIWindow *window = nil;
    for (window in app.windows) 
    {
        if ([self _getKeyboardViewFromWindow:window]) return window;
    }
    window = app.keyWindow;
    if ([self _getKeyboardViewFromWindow:window]) return window;
    
    NSMutableArray *kbWindows = nil;
    for (window in app.windows) 
    {
        NSString *windowName = NSStringFromClass(window.class);
        if ([self _systemVersion] < 9)
        {   // UITextEffectsWindow
            if (windowName.length == 19 &&
                [windowName hasPrefix:@"UI"] &&
                [windowName hasSuffix:@"TextEffectsWindow"]) 
            {
                if (!kbWindows) kbWindows = [NSMutableArray new];
                [kbWindows addObject:window];
            }
        } else
        {   // UIRemoteKeyboardWindow
            if (windowName.length == 22 &&
                [windowName hasPrefix:@"UI"] &&
                [windowName hasSuffix:@"RemoteKeyboardWindow"])
            {
                if (!kbWindows) kbWindows = [NSMutableArray new];
                [kbWindows addObject:window];
            }
        }
    }
    
    if (kbWindows.count == 1) return kbWindows.firstObject;
    return nil;
}

//显示
- (void)showX
{  //键盘显示的时候,keyboardWindow才会获取到
    UIWindow *keyboardWindow = [self keyboardWindow];
    if (!keyboardWindow) return;
    UIView *keyboardView = [self keyboardView];
    if (!keyboardView) return;
    CGSize keyboardSize = keyboardView.frame.size;
    CGFloat width = (keyboardSize.width - 7) / 3;
    CGFloat height = (keyboardSize.height - 2) / 4;
    CGFloat y = keyboardWindow.frame.size.height - height;
    _xButton.frame = CGRectMake(0, y, width, height);
    
    //显示动画
   [UIView animateWithDuration:0.3 animations:^{
        _xButton.alpha = 1.0f;
   }];
}

- (void)hideX
{
    UIWindow *keyboardWindow = [self keyboardWindow];
    if (!keyboardWindow) return;
    //获取当前的FirstResponder
    UIView *view = [self findFirstResponderView:self.view];
    if (view)
    {   //如果FirstResponder不为空,则说明只是切换UITextField
        [UIView animateWithDuration:0.3 animations:^{
             _xButton.alpha = 0.0f;
        }];
    }else
    {   //如果FirstResponder为空,则说明键盘消失
        [UIView animateWithDuration:0.3 animations:^{
             _xButton.alpha = 0.0f;
        } completion:^(BOOL finished) {
              if (finished) [_xButton removeFromSuperview];
        }];
    }
}
#pragma mark - UITextFieldDelegate
- (void)textFieldDidBeginEditing:(UITextField *)textField
{   //如果有多个UITextField,需要判断一下textField是否是输入身份证号的UITextField
    //UITextField进入编辑状态和keyboardWillShow的通知几乎是同时的,我们需要在键盘完全显示出来的时候再显示X按钮
    [self performSelector:@selector(showX) withObject:nil afterDelay:0.3];
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
    [self performSelector:@selector(hideX) withObject:nil afterDelay:0];
    return YES;
}

/*
 *  iOS7下,不管怎么切换UITextField都只调用一次
 *  iOS8及以上,因为第三方键盘的问题,有可能会被调用多次
 */
#pragma mark - Notification
- (void)keyboardWillShow:(NSNotification *)notification
{  
    UIWindow *keyboardWindow = [self keyboardWindow];
    if (!keyboardWindow) return;
    if (_xButton.superview) return;//如果X按钮已经被添加
    _xButton.alpha = 0;
    [keyboardWindow addSubview:_xButton];//只能把按钮添加到keyboardWindow上,添加到keyboardView上是无法点击的
}

@end

你可能感兴趣的:(自定义身份证键盘,iOS7+)