文章目录
一、主要方法
1、textField代理方法
- 开始编辑
点击textField,键盘弹出就会回调此代理方法,开始编辑。返回NO,禁止编辑。
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField; // return NO to disallow editing.
- 编辑中
textField点击键盘按键,就会回调这个代理方法。在这个方法返回NO时,键盘点击输入无效。编辑的过程中我们可以对输入内容进行输入控制等。
注意这个方法中取到的textField.text并不是最终的内容,而是需要拼上string。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; // return NO to not change text
- 结束编辑
键盘收起时,结束编辑时候会回调这个代理方法。
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField; // return YES to allow editing to stop and to resign first responder status. NO to disallow the editing session to end
2、textField添加方法
textField是继承UIControl的,所以可以添加target。这个方法是给textField添加的监控其内容变化的方法。
这个方法中取到的textField.text是真实的最终的输入内容。可以在这个方法中做输入长度限制等。
[self.textField addTarget:self action:@selector(textFieldValueChanged:) forControlEvents:UIControlEventEditingChanged];
二、输入限制
1、自动填充输入内容功能
需求:点击输入框,弹出键盘,并自动填充填充公共的输入内容前缀。点击输入框后,自动填充前缀,如果未输入,键盘收起时候清除自动填充的前缀内容。
例如:点击输入框,需要自动填充前4位“edu_”,在textFieldShouldBeginEditing代理方法中做如下处理
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if(textField.text.length<=4)
textField.text = @"edu_";
return YES;
}
用户未输入,收起键盘后,自动填充内容需要清除,这个需求和上面是一起的
- (void)textFieldDidEndEditing:(UITextField *)textField
{
if(textField.text.length<=4) {
textField.text = nil;
}
}
2、输入长度限制
需求:输入长度限制16位
实现:在如下方法中做长度限制,建议不要在代理方法中做长度限制,在代理方法中设置会不准确的,选择键盘推荐的文字的时候,代理方法是不会执行的,限制不住。
- (void)textFieldValueChanged:(UITextField *)textField {
if (textField.text.length >= 12) {
//长度限制16位
textField.text = [textField.text substringToIndex:16];
}
}
3、按钮状态
需求:当输入长度不够时,“下一步”按钮置灰,不可点击,否则按钮可点击并改变颜色。
实现:在内容改变后,做长度限制,有时候会根据长度来设置“下一步”,按钮是否可点击。
- (void)textFieldValueChanged:(UITextField *)textField {
if (textField.text.length >= 12) {
//长度限制12位
textField.text = [textField.text substringToIndex:12];
//输入长度不够时候按钮置灰不可点击
self.nextButton.backgroundColor = UIColorSet(82, 204, 144, 1);
self.nextButton.enabled = YES;
}
else {
self.nextButton.backgroundColor = UIColorSet(220, 244, 232, 1);
self.nextButton.enabled = NO;
}
}
4、空格输入限制
系统有提供过滤字符串首位空格的方法:
过滤字符串首尾空格
NSString *text = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
过滤字符串首位空格以及换行
NSString *text = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
4.1 过滤首位空格
需求:首位不能输入空格,输入完后自动过滤末尾空格。
实现:首位不能输入空格可在输入时限制,末尾不能输入空格,在输入完之后进行末尾空格过滤。
输入限制控制首位不能输入空格:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//限制首位不能输入空格
if (NSEqualRanges(range, NSMakeRange(0, 0)) && [string isEqualToString:@" "]) {
return NO;
}
return YES;
}
4.2 不能输入空格
需求:过滤首位空格
实现:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([string isEqualToString:@" "]) {
return NO;
}
return YES;
}
或者:
- (void)textFieldValueChanged:(UITextField *)textField
{
textField.text = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
5、删除键
不管在什么情况下都需要支持删除,直接在代理方法中判断如果是删除操作,一律返回YES即可。
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//删除键
if ([string isEqualToString:@""]) {
return YES;
}
return YES;
}
6、表情限制
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//删除键
if ([string isEqualToString:@""]) {
return YES;
}
//不能输入表情
if ([[[textField textInputMode] primaryLanguage] isEqualToString:@"emoji"] ||
![[textField textInputMode] primaryLanguage]) {
return NO;
}
return YES;
}
7、纯数字
需求:密码什么的需要输入纯数字这种需求。
这里创建一个筛选条件,09的闭集,invertedSet方法“取反”,得到的集合是非[09]之外的所有字符集合。
_numberSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet];
- 在textFieldValueChanged方法中做限制
- (void)textFieldValueChanged:(UITextField *)textField {
//只能输入纯数字
textField.text = [[textFiled.text componentsSeparatedByCharactersInSet:_numberSet] componentsJoinedByString:@""];
}
- 在代理方法中限制
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//删除键
if ([string isEqualToString:@""]) {
return YES;
}
//只能输入纯数字
NSString *filterString = [[string componentsSeparatedByCharactersInSet:_numberSet] componentsJoinedByString:@""];
if ([filterString isEqualToString:@""]) {
return NO;
}
return YES;
}
在代理方法中做限制会出bug,当用户选择键盘提示文字时,代理方法是不会执行的,也就监听不到输入的内容变化。
三、NSPredicate 和 NSCharacterSet
对于输入限制可以使用NSCharacterSet
类,通过-componentsSeparatedByCharactersInSet:方法将数字提取出来,返回一个数组,然后将这个数组通过-componentsJoinedByString:方法组合成一个新的字符串。
因为数组中都是数字,所以组合成的字符串也是由数字组成的字符串。
这里手机号和验证码输入这样限制,加上将键盘设置成UIKeyboardTypePhonePad
是可行的,但是昵称和输入限制是存在风险的,是有bug的。
苹果系统键盘顶部会有输入时提示文字,当用户选择键盘上方弹出的提示输入文本时,这个代理方法是不会执行的,就会出bug。
出现上面的问题的主要原因是,选择键盘提示的文本,此代理不会被执行,也就监听不到输入内容的合理性。
解决这个问题,将限制统一放在-textFieldValueChanged:方法中去过滤特殊字符,这样就很保险,不会出bug了。
- (void)textFieldValueChanged:(UITextField *)textField {
if (textField == self.nameTextFiled) {
//昵称16位长度限制
if (textField.text.length >= 16) {
textField.text = [textField.text substringToIndex:16];
}
}
else if (textField == self.phoneTextFiled) {
//手机号12位长度限制
if (textField.text.length >= 12) {
textField.text = [textField.text substringToIndex:12];
}
NSString *filterString = [[textField.text componentsSeparatedByCharactersInSet:[[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet]] componentsJoinedByString:@""];
textField.text = filterString;
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//删除键
if ([string isEqualToString:@""]) {
return YES;
}
//限制首位不能输入空格
if (NSEqualRanges(range, NSMakeRange(0, 0)) && [string isEqualToString:@" "]) {
return NO;
}
//限制表情
if ([textField.textInputMode.primaryLanguage isEqualToString:@"emoji"]) {
return NO;
}
if (![[textField textInputMode] primaryLanguage]) {
return NO;
}
//中文、英文、字母
if (textField == self.nameTextFiled) {
NSString *pattern = @"^[➋➌➍➎➏➐➑➒a-zA-Z\u4E00-\u9FA5\\d]*$";
NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
if (![pred evaluateWithObject:string]) {
return NO;
}
}
return YES;
}