Last active
October 24, 2017 19:50
-
-
Save sweetmandm/526bd3e9fe01944dfdd6fbd179b7d472 to your computer and use it in GitHub Desktop.
Simple Phone Number Formatting for String + UITextField
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Usage: | |
// ------ | |
// /* add the action somewhere: */ | |
// phoneTextField.addTarget(self, action: #selector(updatePhoneFormat), for: .editingChanged) | |
// /* implement the update action: */ | |
// func updatePhoneFormat() { phoneTextField.formatPhoneNumber() } | |
import UIKit | |
extension String { | |
var phoneFormat: String { | |
/** | |
* NOTE: This assumes US country code. | |
*/ | |
var text = trimNonNumbers() | |
let length = text.lengthOfBytes(using: .utf8) | |
switch length { | |
case 11 where text.characters.first == "1": | |
// example: `1 (222) 333 4444` | |
text.insert(" ", at: text.index(text.startIndex, offsetBy: 7)) | |
text.insert(contentsOf: ") ".characters, at: text.index(text.startIndex, offsetBy: 4)) | |
text.insert(contentsOf: " (".characters, at: text.index(text.startIndex, offsetBy: 1)) | |
case 8...10 where text.characters.first != "1": | |
// example: `(222) 333 4444` | |
text.insert(contentsOf: " ".characters, at: text.index(text.startIndex, offsetBy: 6)) | |
text.insert(contentsOf: ") ".characters, at: text.index(text.startIndex, offsetBy: 3)) | |
text.insert(contentsOf: "(".characters, at: text.index(text.startIndex, offsetBy: 0)) | |
default: | |
break | |
} | |
return text | |
} | |
func trimNonNumbers() -> String { | |
return components(separatedBy: CharacterSet.decimalDigits.inverted).joined() | |
} | |
} | |
extension UITextField { | |
func formatPhoneNumber() { | |
/** | |
* Note: This dance is to keep the cursor position in the same relative spot | |
* while editing characters in the middle of the phone number. | |
*/ | |
let pos = selectedTextRange?.start | |
let range = textRange(from: beginningOfDocument, to: pos ?? endOfDocument) | |
let diffBefore: Int = { | |
guard let range = range else { return 0 } | |
let leftOfCursorLength = text(in: range)?.lengthOfBytes(using: .utf8) ?? 0 | |
let leftOfCursorTrimmed = text(in: range)?.trimNonNumbers().lengthOfBytes(using: .utf8) ?? 0 | |
return leftOfCursorTrimmed - leftOfCursorLength | |
}() | |
text = text?.phoneFormat | |
let diffAfter: Int = { | |
guard let range = range else { return 0 } | |
let leftOfCursorLength = text(in: range)?.lengthOfBytes(using: .utf8) ?? 0 | |
let leftOfCursorTrimmed = text(in: range)?.trimNonNumbers().lengthOfBytes(using: .utf8) ?? 0 | |
let temp = leftOfCursorTrimmed - leftOfCursorLength | |
guard | |
let pos = pos, | |
let newPos = position(from: pos, offset: -temp), | |
let newRange = textRange(from: beginningOfDocument, to: newPos) | |
else { | |
return temp | |
} | |
let newLeftOfCursorLength = text(in: newRange)?.lengthOfBytes(using: .utf8) ?? 0 | |
let newLeftOfCursorTrimmed = text(in: newRange)?.trimNonNumbers().lengthOfBytes(using: .utf8) ?? 0 | |
return newLeftOfCursorTrimmed - newLeftOfCursorLength | |
}() | |
if let oldPos = pos, let newPos = position(from: oldPos, offset: diffBefore - diffAfter) { | |
selectedTextRange = textRange(from: newPos, to: newPos) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment