BYPhoneNumTF 一个电话号码格式的文本框

功能

当在TextField输入数字时,会自动分隔为:137 9922 2299 或 137-9922-2299

限制文本输入个数

限制只能输入数字

效果:

实现方法

要实现电话号码格式的输入看似简单,但是实现起来坑非常多,至于坑是什么只有各位动手写了才能体会~

下面我们来实现该功能:

首先要遵守协议<UITextFieldDelegate>

然后在- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 方法中实现我们的逻辑

代码:

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#import "LoginVC.h"

#define placeholder @" "

@interface LoginVC () <UITextFieldDelegate>

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

@end


- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

NSString *phStr = placeholder;
unichar phChar = ' ';
if (phStr.length) {
phChar = [phStr characterAtIndex:0];
}


if (textField) {
NSString* text = textField.text;
//删除
if([string isEqualToString:@""]){

//删除一位
if(range.length == 1){
//最后一位,遇到空格则多删除一次
if (range.location == text.length - 1 ) {
if ([text characterAtIndex:text.length - 1] == phChar) {
[textField deleteBackward];
}
return YES;
}
//从中间删除
else{
NSInteger offset = range.location;

if (range.location < text.length && [text characterAtIndex:range.location] == phChar && [textField.selectedTextRange isEmpty]) {
[textField deleteBackward];
offset --;
}
[textField deleteBackward];
textField.text = [self _parseString:textField.text];
UITextPosition *newPos = [textField positionFromPosition:textField.beginningOfDocument offset:offset];
textField.selectedTextRange = [textField textRangeFromPosition:newPos toPosition:newPos];
return NO;
}
}
else if (range.length > 1) {
BOOL isLast = NO;
//如果是从最后一位开始
if(range.location + range.length == textField.text.length ){
isLast = YES;
}
[textField deleteBackward];
textField.text = [self _parseString:textField.text];

NSInteger offset = range.location;
if (range.location == 3 || range.location == 8) {
offset ++;
}
if (isLast) {
//光标直接在最后一位了
}else{
UITextPosition *newPos = [textField positionFromPosition:textField.beginningOfDocument offset:offset];
textField.selectedTextRange = [textField textRangeFromPosition:newPos toPosition:newPos];
}

return NO;
}

else{
return YES;
}
}

else if(string.length >0){

//限制输入字符个数
if (([self _noneSpaseString:textField.text].length + string.length - range.length > 11) ) {
return NO;
}

//判断是否是纯数字(搜狗,百度输入法,数字键盘居然可以输入其他字符)
if(![self _isNum:string]){
return NO;
}
[textField insertText:string];
textField.text = [self _parseString:textField.text];

NSInteger offset = range.location + string.length;
if (range.location == 3 || range.location == 8) {
offset ++;
}
UITextPosition *newPos = [textField positionFromPosition:textField.beginningOfDocument offset:offset];
textField.selectedTextRange = [textField textRangeFromPosition:newPos toPosition:newPos];
return NO;
}else{
return YES;
}

}

return YES;


}

- (NSString*)_parseString:(NSString*)string{

if (!string) {
return nil;
}
NSMutableString* mStr = [NSMutableString stringWithString:[string stringByReplacingOccurrencesOfString:placeholder withString:@""]];
if (mStr.length >3) {
[mStr insertString:placeholder atIndex:3];
}if (mStr.length > 8) {
[mStr insertString:placeholder atIndex:8];

}

return mStr;

}

/** 获取正常电话号码(去掉空格) */
- (NSString*)_noneSpaseString:(NSString*)string{

return [string stringByReplacingOccurrencesOfString:placeholder withString:@""];

}

- (BOOL)_isNum:(NSString *)checkedNumString {

if (!checkedNumString) {
return NO;
}

checkedNumString = [checkedNumString stringByTrimmingCharactersInSet:[NSCharacterSet decimalDigitCharacterSet]];

if(checkedNumString.length > 0) {
return NO;
}

return YES;

}

封装方法

需要实现的代码就是要这么多,但这些代码写在ViewController显得太臃肿了,所以我对代码进行了封装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//
// BYPhoneNumTF.h
//
// Created by BY on 16/12/2.
// Copyright © 2016年 BY. All rights reserved.
// 电话号码类型的文本输入框,且只能输入数字
// 输入显示:137 9922 1234 或 137-9922-1234
// 使用方法:在XIB中的TextField继承该类即可
// 修改占位符placeholder即可改变样式

#import <UIKit/UIKit.h>

// @" " or @"-"
#define placeholder @" "

@interface BYPhoneNumTF : UITextField

/** 去掉格式的电话号码 */
@property (nonatomic, strong) NSString *plainPhoneNum;

@end
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
//
// BYPhoneNumTF.m
// dev-Jack
//
// Created by BY on 16/12/2.
// Copyright © 2016年 Jack. All rights reserved.
//

#import "BYPhoneNumTF.h"


@interface BYPhoneNumTF ()<UITextFieldDelegate>

@end

@implementation BYPhoneNumTF

- (NSString *)plainPhoneNum {
return [self _noneSpaseString:self.text];
}

- (void)awakeFromNib {
[super awakeFromNib];
self.delegate = self;
}


- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

NSString *phStr = placeholder;
unichar phChar = ' ';
if (phStr.length) {
phChar = [phStr characterAtIndex:0];
}


if (textField) {
NSString* text = textField.text;
//删除
if([string isEqualToString:@""]){

//删除一位
if(range.length == 1){
//最后一位,遇到空格则多删除一次
if (range.location == text.length - 1 ) {
if ([text characterAtIndex:text.length - 1] == phChar) {
[textField deleteBackward];
}
return YES;
}
//从中间删除
else{
NSInteger offset = range.location;

if (range.location < text.length && [text characterAtIndex:range.location] == phChar && [textField.selectedTextRange isEmpty]) {
[textField deleteBackward];
offset --;
}
[textField deleteBackward];
textField.text = [self _parseString:textField.text];
UITextPosition *newPos = [textField positionFromPosition:textField.beginningOfDocument offset:offset];
textField.selectedTextRange = [textField textRangeFromPosition:newPos toPosition:newPos];
return NO;
}
}
else if (range.length > 1) {
BOOL isLast = NO;
//如果是从最后一位开始
if(range.location + range.length == textField.text.length ){
isLast = YES;
}
[textField deleteBackward];
textField.text = [self _parseString:textField.text];

NSInteger offset = range.location;
if (range.location == 3 || range.location == 8) {
offset ++;
}
if (isLast) {
//光标直接在最后一位了
}else{
UITextPosition *newPos = [textField positionFromPosition:textField.beginningOfDocument offset:offset];
textField.selectedTextRange = [textField textRangeFromPosition:newPos toPosition:newPos];
}

return NO;
}

else{
return YES;
}
}

else if(string.length >0){

//限制输入字符个数
if (([self _noneSpaseString:textField.text].length + string.length - range.length > 11) ) {
return NO;
}

//判断是否是纯数字(搜狗,百度输入法,数字键盘居然可以输入其他字符)
if(![self _isNum:string]){
return NO;
}
[textField insertText:string];
textField.text = [self _parseString:textField.text];

NSInteger offset = range.location + string.length;
if (range.location == 3 || range.location == 8) {
offset ++;
}
UITextPosition *newPos = [textField positionFromPosition:textField.beginningOfDocument offset:offset];
textField.selectedTextRange = [textField textRangeFromPosition:newPos toPosition:newPos];
return NO;
}else{
return YES;
}

}

return YES;


}

- (NSString*)_parseString:(NSString*)string{

if (!string) {
return nil;
}
NSMutableString* mStr = [NSMutableString stringWithString:[string stringByReplacingOccurrencesOfString:placeholder withString:@""]];
if (mStr.length >3) {
[mStr insertString:placeholder atIndex:3];
}if (mStr.length > 8) {
[mStr insertString:placeholder atIndex:8];

}

return mStr;

}

/** 获取正常电话号码(去掉空格) */
- (NSString*)_noneSpaseString:(NSString*)string{

return [string stringByReplacingOccurrencesOfString:placeholder withString:@""];

}

- (BOOL)_isNum:(NSString *)checkedNumString {

if (!checkedNumString) {
return NO;
}

checkedNumString = [checkedNumString stringByTrimmingCharactersInSet:[NSCharacterSet decimalDigitCharacterSet]];

if(checkedNumString.length > 0) {
return NO;
}

return YES;

}


@end

使用方法

在storyboard中的TextField控件的Calss类型选择该类BYPhoneNumTF即可。

代码及Demo下载地址:BYPhoneNumTF