@@ -13,7 +13,6 @@ import UIKit
13
13
}
14
14
15
15
open class FormattedTextField : UITextField {
16
- open static let maskSymbol : Character = " × "
17
16
18
17
public override init ( frame: CGRect ) {
19
18
placeholderLabel = UILabel ( )
@@ -34,8 +33,11 @@ open class FormattedTextField: UITextField {
34
33
super. delegate = delegateProxy
35
34
36
35
if let unformattedText = unformattedText {
37
- var cursorPosition = 0
38
- text = formattedText ( fromText: unformattedText, textMask: text, cursorPosition: & cursorPosition)
36
+ if let formatter = textFormatter {
37
+ text = formatter. formattedText ( from: unformattedText)
38
+ } else {
39
+ text = unformattedText
40
+ }
39
41
}
40
42
41
43
placeholderLabel. font = font
@@ -48,22 +50,26 @@ open class FormattedTextField: UITextField {
48
50
addSubview ( placeholderLabel)
49
51
}
50
52
51
- @IBInspectable open var textMask : String ? {
52
- didSet( oldMask) {
53
- var cursorPosition : Int = 0
54
- if let selectedRange = selectedCharactersRange, let text = text {
55
- cursorPosition = text. distance ( from: text. startIndex, to: selectedRange. lowerBound)
56
- } else {
57
- cursorPosition = 0
53
+ @IBInspectable open var textFormatter : TextFromatter ? {
54
+ didSet( oldFormatter) {
55
+ let text = ( self . text ?? " " )
56
+ let selectedRange = selectedCharactersRange ?? text. startIndex..< text. startIndex
57
+
58
+ var unformattedText = text
59
+ var unformattedRange = selectedRange
60
+ if let oldFormatter = oldFormatter {
61
+ ( unformattedText, unformattedRange) = oldFormatter. unformattedText ( from: text, range: selectedRange)
58
62
}
59
63
60
- let unformattedText = unformatterText ( fromText: ( text ?? " " ) , textMask: oldMask, cursorPosition: & cursorPosition)
61
- let newFormattedText = formattedText ( fromText: unformattedText, textMask: textMask, cursorPosition: & cursorPosition)
62
- text = newFormattedText
64
+ var formattedText = unformattedText
65
+ var formattedRange = unformattedRange
66
+ if let formatter = textFormatter {
67
+ ( formattedText, formattedRange) = formatter. formattedText ( from: unformattedText, range: unformattedRange)
68
+ }
63
69
70
+ self . text = formattedText
64
71
if selectedTextRange != nil {
65
- let cursorIndex = newFormattedText. index ( newFormattedText. startIndex, offsetBy: cursorPosition, limitedBy: newFormattedText. endIndex) ?? newFormattedText. endIndex
66
- selectedCharactersRange = cursorIndex..< cursorIndex
72
+ selectedCharactersRange = formattedRange. upperBound..< formattedRange. upperBound
67
73
}
68
74
}
69
75
}
@@ -73,21 +79,25 @@ open class FormattedTextField: UITextField {
73
79
guard let text = text else {
74
80
return nil
75
81
}
76
- var cursorPosition = 0
77
- let unformattedText = self . unformatterText ( fromText: text, textMask: textMask, cursorPosition: & cursorPosition)
82
+ guard let formatter = textFormatter else {
83
+ return text
84
+ }
85
+ let unformattedText = formatter. unformattedText ( from: text)
78
86
79
87
return unformattedText
80
88
}
81
89
set ( value) {
82
- var cursorPosition = 0
83
- let unformattedText = value ?? " "
84
- let formattedText = self . formattedText ( fromText: unformattedText, textMask: textMask, cursorPosition: & cursorPosition)
90
+ var formattedText = ( value ?? " " )
91
+ if let formatter = textFormatter {
92
+ formattedText = formatter. formattedText ( from: formattedText)
93
+ }
94
+
85
95
if formattedText. characters. count > 0 || value != nil {
86
96
text = formattedText
87
97
} else {
88
98
text = nil
89
99
}
90
- placeholderLabel. isHidden = ( unformattedText . characters. count > 0 )
100
+ placeholderLabel. isHidden = ( formattedText . characters. count > 0 )
91
101
}
92
102
}
93
103
@@ -96,7 +106,7 @@ open class FormattedTextField: UITextField {
96
106
return super. attributedText
97
107
}
98
108
set ( value) {
99
- assert ( false , " masked text field unsupports attributed text " )
109
+ assertionFailure ( " masked text field unsupports attributed text " )
100
110
}
101
111
}
102
112
@@ -141,13 +151,12 @@ open class FormattedTextField: UITextField {
141
151
super. layoutSubviews ( )
142
152
143
153
var placeholderFrame = self . placeholderRect ( forBounds: bounds)
144
- if let mask = textMask, let firstMaskSymbolRange = mask. range ( of: String ( maskSymbol) ) {
145
- let prefix = mask [ mask. startIndex..< firstMaskSymbolRange. lowerBound]
154
+ if let text = self . text {
146
155
var attributes : [ String : Any ] ? = nil
147
156
if let placeholderFont = font {
148
157
attributes = [ NSFontAttributeName: placeholderFont]
149
158
}
150
- let prefixWidth = ( prefix as NSString ) . size ( attributes: attributes) . width
159
+ let prefixWidth = ( text as NSString ) . size ( attributes: attributes) . width
151
160
placeholderFrame. origin. x += prefixWidth
152
161
placeholderFrame. size. width -= prefixWidth
153
162
}
@@ -156,9 +165,6 @@ open class FormattedTextField: UITextField {
156
165
157
166
// MARK: - Private
158
167
159
- private var maskSymbol : Character {
160
- return type ( of: self ) . maskSymbol
161
- }
162
168
private let placeholderLabel : UILabel
163
169
164
170
private lazy var delegateProxy : TextFieldDelegateProxy = {
@@ -174,137 +180,52 @@ open class FormattedTextField: UITextField {
174
180
return false
175
181
}
176
182
}
183
+ let text = self . text ?? " "
184
+ let charactersRange = text. range ( fromUtf16NsRange: range) !
177
185
178
- let formattedText = text ?? " "
179
- var charachtersRange = formattedText. nsrange ( fromRange: formattedText. range ( fromUtf16NsRange: range) !)
180
-
181
- var cursorPosition : Int
182
- if string. characters. count > 0 {
183
- cursorPosition = NSMaxRange ( charachtersRange)
186
+ let unformattedText : String
187
+ var unformattedRange : Range < String . Index >
188
+ if let formatter = textFormatter {
189
+ ( unformattedText, unformattedRange) = formatter. unformattedText ( from: text, range: charactersRange)
184
190
} else {
185
- charachtersRange = deleteBackwardRange ( fromRange : charachtersRange )
186
- cursorPosition = charachtersRange . location
191
+ unformattedText = text
192
+ unformattedRange = charactersRange
187
193
}
188
194
189
- var unformattedText = unformatterText ( fromText: formattedText, textMask: textMask, cursorPosition: & cursorPosition)
190
- let unformattedRange = self . range ( fromFormattedRange: charachtersRange)
195
+ let isBackspace = ( string. characters. count == 0 && unformattedRange. isEmpty)
196
+ if isBackspace && unformattedRange. lowerBound != unformattedText. startIndex {
197
+ unformattedRange = unformattedText. index ( before: unformattedRange. lowerBound) ..< unformattedRange. upperBound
198
+ }
191
199
192
200
if let originDelegate = ( delegateProxy. delegate as? FormattedTextFieldDelegate ) ,
193
201
originDelegate. responds ( to: #selector( FormattedTextFieldDelegate . textField ( _: shouldChangeUnformattedText: in: replacementString: ) ) ) {
194
-
195
- let utf16UnformattedRange = unformattedText. utf16Nsrange ( fromRange: unformattedText. range ( fromNsRange: unformattedRange) !)
202
+ let utf16UnformattedRange = unformattedText. utf16Nsrange ( fromRange: unformattedRange)
196
203
if !originDelegate. textField!( self , shouldChangeUnformattedText: unformattedText, in: utf16UnformattedRange, replacementString: string) {
197
204
return false
198
205
}
199
206
}
200
207
201
- unformattedText. replaceSubrange ( unformattedText. range ( fromNsRange: unformattedRange) !, with: string)
202
- cursorPosition += string. characters. count
203
- if string. characters. count > 0 {
204
- cursorPosition -= unformattedRange. length
205
- }
208
+ let newUnformattedText = unformattedText. replacingCharacters ( in: unformattedRange, with: string)
209
+ let selectionOffset = unformattedText. distance ( from: unformattedText. startIndex, to: unformattedRange. lowerBound)
210
+ let cursorPosition = newUnformattedText. index ( newUnformattedText. startIndex, offsetBy: selectionOffset + string. characters. count)
206
211
207
- let newFormattedText = self . formattedText ( fromText: unformattedText, textMask: textMask, cursorPosition: & cursorPosition)
208
- text = newFormattedText
209
- placeholderLabel. isHidden = ( unformattedText. characters. count > 0 )
212
+ let formattedText : String
213
+ let formattedRange : Range < String . Index >
214
+ if let formatter = textFormatter {
215
+ ( formattedText, formattedRange) = formatter. formattedText ( from: newUnformattedText, range: cursorPosition..< cursorPosition)
216
+ } else {
217
+ formattedText = newUnformattedText
218
+ formattedRange = cursorPosition..< cursorPosition
219
+ }
220
+ self . text = formattedText
221
+ selectedCharactersRange = formattedRange. upperBound..< formattedRange. upperBound
210
222
211
- cursorPosition = min ( cursorPosition, newFormattedText. characters. count)
212
- let cursorIndex = newFormattedText. index ( newFormattedText. startIndex, offsetBy: cursorPosition)
213
- selectedCharactersRange = cursorIndex..< cursorIndex
223
+ placeholderLabel. isHidden = ( newUnformattedText. characters. count > 0 )
214
224
215
225
sendActions ( for: . editingChanged)
216
226
217
227
return false
218
228
}
219
-
220
- private func unformatterText( fromText text: String , textMask: String ? , cursorPosition: inout Int ) -> String {
221
- guard let mask = textMask else {
222
- return text
223
- }
224
- let originCursorPosition = cursorPosition
225
-
226
- var unformattedText = String ( )
227
- for i in 0 ..< ( min ( mask. characters. count, text. characters. count) ) {
228
- let maskCharacter = mask. characters [ mask. index ( mask. startIndex, offsetBy: i) ]
229
- if maskCharacter == maskSymbol {
230
- let textCharacter = text. characters [ text. index ( text. startIndex, offsetBy: i) ]
231
- unformattedText. append ( textCharacter)
232
- } else if i < originCursorPosition {
233
- cursorPosition -= 1
234
- }
235
- }
236
-
237
- return unformattedText
238
- }
239
-
240
- private func formattedText( fromText text: String , textMask: String ? , cursorPosition: inout Int ) -> String {
241
- guard let mask = textMask else {
242
- return text
243
- }
244
- let originCursorPosition = cursorPosition
245
-
246
- var formattedText = String ( )
247
- var textIndex = 0
248
- for maskCharacter in mask. characters {
249
- if maskCharacter == maskSymbol {
250
- if textIndex >= text. characters. count {
251
- break
252
- }
253
- let textCharacter = text. characters [ text. index ( text. startIndex, offsetBy: textIndex) ]
254
- formattedText. append ( textCharacter)
255
- textIndex += 1
256
- } else {
257
- formattedText. append ( maskCharacter)
258
- if textIndex <= originCursorPosition {
259
- cursorPosition += 1
260
- }
261
- }
262
- }
263
-
264
- return formattedText
265
- }
266
-
267
- private func range( fromFormattedRange range: NSRange ) -> NSRange {
268
- guard let mask = textMask else {
269
- return range
270
- }
271
-
272
- let maskCharactersRange = mask. range ( fromNsRange: range) !
273
- var location = 0
274
- for character in mask [ mask. startIndex..< maskCharactersRange. lowerBound] . characters {
275
- if character == maskSymbol {
276
- location += 1
277
- }
278
- }
279
- var length = 0
280
- for character in mask [ maskCharactersRange] . characters {
281
- if character == maskSymbol {
282
- length += 1
283
- }
284
- }
285
- return NSMakeRange ( location, length)
286
- }
287
-
288
- private func deleteBackwardRange( fromRange range: NSRange ) -> NSRange {
289
- guard let mask = self . textMask else {
290
- return range
291
- }
292
- let charactersRange = mask. range ( fromNsRange: range) !
293
- if mask [ charactersRange] . contains ( String ( maskSymbol) ) {
294
- return range
295
- }
296
-
297
- let searchRange = mask. startIndex..< charactersRange. lowerBound
298
-
299
- let deleteRange : Range < String . Index >
300
- if let removedSymbolRange = mask. range ( of: String ( maskSymbol) , options: . backwards, range: searchRange, locale: nil ) {
301
- deleteRange = removedSymbolRange. lowerBound..< charactersRange. upperBound
302
- } else {
303
- deleteRange = charactersRange. upperBound..< charactersRange. upperBound
304
- }
305
-
306
- return mask. nsrange ( fromRange: deleteRange)
307
- }
308
229
}
309
230
310
231
// MARK: - TextFieldDelegateProxy
0 commit comments