一、应用场景
很多情况下我们的输入都是有硬性要求的,比如只能输入数字,通常情况下我们的解决方案就是指定输入框的键盘模式(keyboardType),可系统提供给我的键盘种类还是非常有限的,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | typedef NS_ENUM(NSInteger, UIKeyboardType) { ????UIKeyboardTypeDefault,??????????????? // Default type for the current input method. ????UIKeyboardTypeASCIICapable,?????????? // Displays a keyboard which can enter ASCII characters, non-ASCII keyboards remain active ????UIKeyboardTypeNumbersAndPunctuation,? // Numbers and assorted punctuation. ????UIKeyboardTypeURL,??????????????????? // A type optimized for URL entry (shows . / .com prominently). ????UIKeyboardTypeNumberPad,????????????? // A number pad (0-9). Suitable for PIN entry. ????UIKeyboardTypePhonePad,?????????????? // A phone pad (1-9, *, 0, #, with letters under the numbers). ????UIKeyboardTypeNamePhonePad,?????????? // A type optimized for entering a person's name or phone number. ????UIKeyboardTypeEmailAddress,?????????? // A type optimized for multiple email address entry (shows space @ . prominently). ????UIKeyboardTypeDecimalPad NS_ENUM_AVAILABLE_IOS(4_1),?? // A number pad with a decimal point. ????UIKeyboardTypeTwitter NS_ENUM_AVAILABLE_IOS(5_0),????? // A type optimized for twitter text entry (easy access to @ #) ????UIKeyboardTypeWebSearch NS_ENUM_AVAILABLE_IOS(7_0),??? // A default keyboard type with URL-oriented addition (shows space . prominently). ? ????UIKeyboardTypeAlphabet = UIKeyboardTypeASCIICapable, // Deprecated ? }; |
有时候可能不能满足我们的需要,比如在数字键盘中需要增加一个完成按钮等等,我们在现有的键盘上动手脚都无法完美解决我们所遇到的问题,最好的办法就是自定义一个符合我们需求的键盘。
二、示例效果
如何能实现这种效果呢,其实使用非常简单,就一行代码:
1 | self.textField.keyboardType = SAKeyboardTypeNumber; |
三、设计原理
3.1、类似于UITextField这样的文本输入控件,一般都有一个inputView属性,这个属性就是用来指定自定义键盘的,还有一个inputAccessoryView属性,用来在键盘上方增加自定义的工具条或控件,我们自定义键盘就从inputView这个属性上做文章。
3.2、然而在使用的时候,我又希望能保持系统风格,即通过setKeyboardType:这个方法,或者改变keyboardType这个枚举值来达到指定自定义键盘的目的,看起来一切都是那么的自然,就好像扩展了系统键盘类型这种效果,我个人认为这种封装是最好的,不用改变开发者的使用习惯!
3.3、由于要改变setKeyboardType:这个方法,无法通过Category实现,只能自定义一个TextField继承自UITextField来覆盖这个方法,如果不想这样做,那就只能通过inputView属性来实现,我这里只介绍前者,我认为重写没什么不好,并且项目上很多系统的类都是需要重写的,重写可以统一风格,统一调整,重写还可以积累自己的一些好用的东西,最终可以积累出一个属于自己的库!
3.4、另外一点,这个键盘需要事先通过xib画好,每一个键可以使用按钮来实现,排版布局这里不做太多说明,实现输入则是调用TextField的replaceRange:withText这个就去来实现
四、代码说明
SATextField.m
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 | // //? SATextField.m //? Test // //? Created by 余西安 on 15/5/16. //? Copyright (c) 2015年 Sian. All rights reserved. // ? #import "SATextField.h" #import "SANumberKeyboard.h" ? @implementation SATextField ? - (void)setKeyboardType:(SAKeyboardType)keyboardType { ????switch (keyboardType) { ????????case SAKeyboardTypeNumber:{ ????????????SANumberKeyboard *keyboard = [SANumberKeyboard keyboardWithTextField:self]; ????????????self.inputView = keyboard; ????????????? ????????}break; ????????????? ????????default: [super setKeyboardType:(UIKeyboardType)keyboardType]; break; ????} } ? @end |
SANumberKeyboard.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | // //? SANumberKeyboard.m //? Test // //? Created by 余西安 on 15/5/16. //? Copyright (c) 2015年 Sian. All rights reserved. // ? #import "SANumberKeyboard.h" ? @implementation SANumberKeyboard ? + (instancetype)keyboardWithTextField:(SATextField *)textField; { ????SANumberKeyboard *keyboard = [[self alloc] init]; ????keyboard.textField = textField; ????return keyboard; } ? - (instancetype)init { ????self = [[[NSBundle mainBundle] loadNibNamed:@"SANumberKeyboard" owner:nil options:nil] firstObject]; ????for (UIButton *btn in self.subviews) { ????????if (btn.tag == 0) continue; ????????UIImage *image = [self imageWithColor:[UIColor whiteColor]]; ????????UIImage *image1 = [self imageWithColor:[UIColor colorWithWhite:0.8 alpha:1.0]]; ????????if (btn.tag <= 10)[btn setBackgroundImage:image forState:UIControlStateNormal]; ????????if (btn.tag > 10)[btn setBackgroundImage:image1 forState:UIControlStateNormal]; ????????[btn addTarget:self action:@selector(buttonEven:) forControlEvents:UIControlEventTouchUpInside]; ????} ????return self; } ? /// 指定颜色生成一张大小为(1,1)的图片 - (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)buttonEven:(UIButton *)button { ????UITextRange *textRange = self.textField.selectedTextRange; ????NSString *string = @""; ????switch (button.tag) { ????????case? 1: string = @"1"; break; ????????case? 2: string = @"2"; break; ????????case? 3: string = @"3"; break; ????????case? 4: string = @"4"; break; ????????case? 5: string = @"5"; break; ????????case? 6: string = @"6"; break; ????????case? 7: string = @"7"; break; ????????case? 8: string = @"8"; break; ????????case? 9: string = @"9"; break; ????????case 10: string = @"0"; break; ????????case 11: string = @"."; break; ????????case 12:{ ????????????if (textRange.isEmpty){ ????????????????UITextPosition *from = [self.textField positionFromPosition:textRange.start offset:-1]; ????????????????UITextPosition *to = [self.textField positionFromPosition:textRange.start offset:0]; ????????????????textRange = [self.textField textRangeFromPosition:from toPosition:to]; ????????????} ????????}break; ????????default:break; ????} ????[self.textField replaceRange:textRange withText:string]; } ? @end |
五、源码下载(Demo)