I am using UITextField and i want that should take character in the format of xx-xx-xxx only numbers.
any help ?
If you want it to be something like a date then you can make your own date formatter like this:
NSDateFormatter *formatter;
NSString *dateString;
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"dd-MM-yyyy HH:mm"]; //or something in your own style
dateString = [formatter stringFromDate:[NSDate date]];
[formatter release]; // maybe; you might want to keep the formatter
// if you're doing this a lot.
Getting Current Time in string in Custom format in objective c
Swift kind of long method but works fine: iOS 8
ViewController // programming mark ----- ----- ---- ----- ----- ---- ----- ----- ----
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.tfCardNumber.addTarget(self, action: "creditCardNumberFormatter:", forControlEvents: .EditingChanged)
self.tfExpiryValue.addTarget(self, action: "creditCardExpiryFormatter:", forControlEvents: .EditingChanged)
}// end viewDidAppear
func creditCardNumberFormatter(sender: AnyObject!) {
// create object universally access global methods
var objMethodInc = MethodInc(object: self)
var formattedText = objMethodInc.formatCreditCard(self.tfCardNumber.text)
if formattedText != self.tfCardNumber.text {
self.tfCardNumber.text = formattedText
}
if countElements(self.tfCardNumber.text) == 19 {
self.tfCardNumber.resignFirstResponder()
self.tfExpiryValue.becomeFirstResponder()
}
}// end creditCardNumberFormatter
func creditCardExpiryFormatter(sender: AnyObject!) {
// create object universally access global methods
var objMethodInc = MethodInc(object: self)
var formattedText = objMethodInc.formatCreditCardExpiry(self.tfExpiryValue.text)
if formattedText != self.tfExpiryValue.text {
self.tfExpiryValue.text = formattedText
}
}// end creditCardExpiryFormatter
// prgm mark --- ---- --- ----
// delegate for textfield
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange
, replacementString string: String) -> Bool {
if string == "" {
return true
}
if textField == self.tfCardNumber {
if countElements(self.tfCardNumber.text) > 18 {
return false
} else if textField == self.tfExpiryValue {
if countElements(self.tfExpiryValue.text) > 4 {
return false
}
}
}
return true
}// end textField
----------- INSIDE your command method or file --------
// prgm mark ----
func formatCreditCard(input: NSString) -> String {
var input = self.trimSpecialCharacters(input);
println("formatCreditCard input \(input)")
var output : NSString?
switch (input.length) {
case 1: output = input
case 2: output = input
case 3: output = input
case 4:
var vs = input.substringToIndex(input.length)
output = NSString(string: "\(vs)")
break
case 5: output = input
case 6: output = input
case 7: output = input
case 8:
var vs1 = input.substringToIndex(4)
var vs2 = input.substringFromIndex(4)
output = NSString(string: "\(vs1)-\(vs2)")
break
case 9: output = input
case 10: output = input
case 11: output = input
case 12:
var vs1 = input.substringToIndex(4)
var vs2 = input.substringWithRange(NSMakeRange(4, 4))
var vs3 = input.substringFromIndex(8)
output = NSString(string: "\(vs1)-\(vs2)-\(vs3)")
break
case 13: output = input
case 14: output = input
case 15: output = input
case 16:
var vs1 = input.substringToIndex(4)
var vs2 = input.substringWithRange(NSMakeRange(4, 4))
var vs3 = input.substringWithRange(NSMakeRange(8, 4))
var vs4 = input.substringFromIndex(12)
output = NSString(string: "\(vs1)-\(vs2)-\(vs3)-\(vs4)")
break
default:
output = input
break
}// end switch
println("formatCreditCard out \(output!)")
return output!
}// end formatCreditCard
// prgm mark ----
func formatCreditCardExpiry(input: NSString) -> String {
var output : NSString?
var input = self.trimSpecialCharacters(input);
switch (input.length) {
case 1: output = input
case 2:
var vs = input.substringToIndex(input.length)
output = NSString(string: "\(vs)")
break
case 3: output = input
case 4:
var vs1 = input.substringToIndex(2)
var vs2 = input.substringFromIndex(2)
output = NSString(string: "\(vs1)/\(vs2)")
break
default:
output = input
break
}
return output!
}// end formatCreditCardExpiry
func trimSpecialCharacters(input: NSString) -> NSString {
var special = NSCharacterSet(charactersInString: "/+-() ")
var comp = input.componentsSeparatedByCharactersInSet(special) as NSArray
return comp.componentsJoinedByString("")
}//end trimSpecialCharacters
My google searches tell me that you should implement
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
from the UITextFieldDelegate
protocol.
Have a look at this for more info.
Here is my take on it after looking at everyone's answers.
Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let separator = "-"
let filler = "X"
if var number = textField.text, string != "" {
number = number.replacingOccurrences(of: separator, with: "")
number = number.replacingOccurrences(of: filler, with: "")
if number.count == 10 { return false }
number += string
while number.count < 10 { number += "X" }
number.insert("-", at: number.index(number.startIndex,
offsetBy: 6))
number.insert("-", at: number.index(number.startIndex,
offsetBy: 3))
textField.text = number
}
return false
}
My solution works like that:
Implement in your textfield delegates:
func textFieldDidBeginEditing(_ textField: UITextField) {
// When you start editing check if there is nothing, in that case add the entire mask
if let text = textField.text, text == "" || text == "DD/MM/YYYY" {
textField.text = "DD/MM/YYYY"
textField.textColor = .lightGray
textField.setCursor(position: text.count)
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard var number = textField.text else {
return true
}
// If user try to delete, remove the char manually
if string == "" {
number.remove(at: number.index(number.startIndex, offsetBy: range.location))
}
// Remove all mask characters
number = number.replacingOccurrences(of: "/", with: "")
number = number.replacingOccurrences(of: "D", with: "")
number = number.replacingOccurrences(of: "M", with: "")
number = number.replacingOccurrences(of: "Y", with: "")
// Set the position of the cursor
var cursorPosition = number.count+1
if string == "" {
//if it's delete, just take the position given by the delegate
cursorPosition = range.location
} else {
// If not, take into account the slash
if cursorPosition > 2 && cursorPosition < 5 {
cursorPosition += 1
} else if cursorPosition > 4 {
cursorPosition += 2
}
}
// Stop editing if we have rich the max numbers
if number.count == 8 { return false }
// Readd all mask char
number += string
while number.count < 8 {
if number.count < 2 {
number += "D"
} else if number.count < 4 {
number += "M"
} else {
number += "Y"
}
}
number.insert("/", at: number.index(number.startIndex, offsetBy: 4))
number.insert("/", at: number.index(number.startIndex, offsetBy: 2))
// Some styling
let enteredTextAttribute = [NSForegroundColorAttributeName: UIColor.black, NSFontAttributeName: UIFont.systemFont(ofSize: 15)]
let maskTextAttribute = [NSForegroundColorAttributeName: UIColor.lightGray, NSFontAttributeName: UIFont.systemFont(ofSize: 15)]
let partOne = NSMutableAttributedString(string: String(number.prefix(cursorPosition)), attributes: enteredTextAttribute)
let partTwo = NSMutableAttributedString(string: String(number.suffix(number.count-cursorPosition)), attributes: maskTextAttribute)
let combination = NSMutableAttributedString()
combination.append(partOne)
combination.append(partTwo)
textField.attributedText = combination
textField.setCursor(position: cursorPosition)
return false
}
func textFieldDidEndEditing(_ textField: UITextField) {
if let text = textField.text, text != "" && text != "DD/MM/YYYY" {
// Do something with your value
} else {
textField.text = ""
}
}
And that little helper as an extension:
extension UITextField {
func setCursor(position: Int) {
let position = self.position(from: beginningOfDocument, offset: position)!
selectedTextRange = textRange(from: position, to: position)
}
}
PS: there is still a bug in that implementation when you try to move the cursor while editing
This worked for me after a little bit of customization from one of the answers.
extension String {
func applyPatternOnNumbers(pattern: String, filler: Character) -> String {
var pureNumber = self.replacingOccurrences( of: "[^0-9]", with: "", options: .regularExpression)
// Insert filler for all occurances of filler in pattern
for index in pattern.indices {
print(pattern[index])
let patternChar = pattern[index]
if patternChar == filler {
if index <= pureNumber.endIndex {
pureNumber.insert(filler, at: index)
}
}
}
return pureNumber
}
}
Usage:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if(text == "\n") {
textView.resignFirstResponder()
return false
} else if !text.isEmpty {
guard let text = textView.text else { return true }
textView.text = text.applyPatternOnNumbers(pattern: "###-##-####", filler: "-")
}
return true
}