I am trying show popOver for my one of textFields, I want to when tap textField for showing pop over keyboard not showing and I can change text field text with popOver, but when tap to text field, text field resign first responder not work there is my code.
func textDidBeginEditing(sender:UITextField) -> Void
{
showPopOver()
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
var maxLength = Int()
var newString = NSString()
if textField == textField1 {
maxLength = 2
let currentString: NSString = textField.text!
if string.characters.count > 0 {
newString = currentString.stringByReplacingCharactersInRange(range, withString: string)
}
}
else if textField == textField2 {
textField2.resignFirstResponder()
showPopOver()
}
else if textField == textField3 {
maxLength = 3
let currentString: NSString = textField.text!
if string.characters.count > 0 {
newString = currentString.stringByReplacingCharactersInRange(range, withString: string)
}
}
else if textField == textField4 {
maxLength = 2
let currentString: NSString = textField.text!
if string.characters.count > 0 {
newString = currentString.stringByReplacingCharactersInRange(range, withString: string)
}
}
return newString.length <= maxLength
}
Related
I am doing validation on my UITextField. It should accept only number and . character. Basically user can enter any decimal number like :
1.0
1.23
1.45
12.47
Also I have to add % sign while editing in textfield like below:
When User enter 1, textfield should update 1 %
When User enter 1.2, textfield should update 1.2 %
When User enter 18.345, textfield should update 18.345 %
I am using below Code to achieve this:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
if string.characters.count == 0 {
return true
}
do {
if textField == self.questionTextFeild {
let nString = textField.text as NSString?
let newString = nString?.replacingCharacters(in: range, with: string)
let expression = "^([0-9]+)?(\\.([0-9]{1,8})?)?$"
let regex = try NSRegularExpression(pattern: expression, options: .caseInsensitive)
let numberOfMatches = regex.numberOfMatches(in: newString! as String, options: [], range: NSRange(location: 0, length: (newString?.characters.count)!))
//textField.text = textField.text!
if numberOfMatches == 0 {
return false
}
}
}
catch let error {
}
return true
}
Using this I can able to enter numbers and dot character. My problem is how can I add % sign? Please suggest me.
Please find the updated code for adding percentage to last of the number while typing
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
if string.count == 0 {
return true
}
do {
if textField == textField {
let nString = textField.text as NSString?
let newString = nString?.replacingCharacters(in: range, with: string)
if var textString = textField.text {
let unitString = " %"
if textString.contains(unitString) {
textString = textString.replacingOccurrences(of: unitString, with: "")
textString += string + unitString
textField.text = textString
} else {
textField.text = string + unitString
}
}
let expression = "^([0-9]+)?(\\.([0-9]{1,8})?)?$"
let regex = try NSRegularExpression(pattern: expression, options: .caseInsensitive)
let numberOfMatches = regex.numberOfMatches(in: newString! as String, options: [], range: NSRange(location: 0, length: (newString?.count)!))
//textField.text = textField.text!
if numberOfMatches == 0 {
return false
}
}
}
catch let error {
print(error.localizedDescription)
}
return true
}
I've a UITextField for entering pincode number.
My requirement is when textField character range reach to 6th character then I've to do server validation and I have to put the data in labels. If character range is less than 5 then I will pass nil value.
Below is my code :-
//TextField character range
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == pinCode
{
guard let text = textField.text else { return true }
let newLength = text.characters.count + string.characters.count - range.length
if(5 >= newLength)
{
print(newLength)
}
else
{
if newLength == 6
{
serverValidation()
print(textField.text!)
setFields(city: "Ajmer", state: "Rajasthan", country: "India")
return newLength <= 6
}
else
{
return newLength <= 6
}
}
}
return true
}
My problem is when (newLength == 6) then I'm getting textField text of 5 characters only. I mean if suppose zip code is 560068 then text I'm getting 56006 only. (But I've to do server validation in that condition only for 6 characters zip code)
So if (newLength == 6) then how can I get 6 characters in text field, and then I can do server validation here only.
I'm new in swift.
Thanks
shouldChangeCharactersIn will get called prior to getting the actual text in the UITextField
This is how you get the full text from that UITextField
let newString = NSString(string: textField.text!).replacingCharacters(in: range, with: string)
Edit
this is how you can use it
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == pinCode
{
guard let text = textField.text else { return true }
let newString = NSString(string: textField.text!).replacingCharacters(in: range, with: string)
let newLength = newString.characters.count
if(5 >= newLength)
{
print(newLength)
}
else
{
if newLength == 6
{
serverValidation()
print(newString)
setFields(city: "Ajmer", state: "Rajasthan", country: "India")
return newLength <= 6
}
else
{
return newLength <= 6
}
}
}
return true
}
Use TextField delegates method for this.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentCharacterCount = textField.text?.characters.count ?? 0
if (range.length + range.location > currentCharacterCount+1)
{
return false
}
print(currentCharacterCount)
let newLength = currentCharacterCount + string.characters.count - range.length
return newLength <= 6 //this will not allow you to enter more than 6 characters
}
After that call
func textFieldDidEndEditing(_ textField: UITextField)
{
print(textField.text!)
setFields(city: "Ajmer", state: "Rajasthan", country: "India")
}
to call this method you can use view.endEditing(true) method.
You should get newlength from textfield.text.length + string.length
then get the text from textfield.text + string.
You can't get new text from textfield.text before call return true.
Try this
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == pinCode
{
guard let text = textField.text else { return true }
var txtAfterUpdate:NSString = textField.text! as NSString
txtAfterUpdate = txtAfterUpdate.stringByReplacingCharactersInRange(range, withString: string)
let txtString = txtAfterUpdate as String
let newLength = txtString.characters.count
if(5 >= newLength)
{
print(newLength)
}
else
{
if newLength == 6
{
print(textField.text!)
setFields(city: "Ajmer", state: "Rajasthan", country: "India")
return newLength <= 6
}
else
{
return newLength <= 6
}
}
}
return true
}
So I want to have a UITextField to only accept digits, solved that by using a custom keyboard input.
The intention of this UITextField is to get someones birthday. I don't want to use an UIDatePicker tough as I don't like it's appearance.
I'd like that the TextField automatically inserts dashes after every second digit that the user put into the TextField.
dd-mm-yy is the placeholder text. I either thought of making the dashes permanently but I don't know how to do that either.
How can I do this?
You want to allow user to enter text in textfield in this dd-mm-yy right ?
if it so i'am sure this will help you.
In top of your class declare this variable which we gonna use later.
var dateFormate = Bool()
Add delegate and tag for that textfield.
Then add this following delegate method
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
//1. To make sure that this is applicable to only particular textfield add tag.
if textField.tag == 1 {
//2. this one helps to make sure that user enters only numeric characters and '-' in fields
let numbersOnly = NSCharacterSet(charactersInString: "1234567890-")
let characterSetFromTextField = NSCharacterSet(charactersInString: string)
let Validate:Bool = numbersOnly .isSupersetOfSet(characterSetFromTextField)
if !Validate {
return false;
}
if range.length + range.location > textField.text?.characters.count {
return false
}
let newLength = (textField.text?.characters.count)! + string.characters.count - range.length
if newLength == 3 || newLength == 6 {
let char = string.cStringUsingEncoding(NSUTF8StringEncoding)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
dateFormate = false;
}else{
dateFormate = true;
}
if dateFormate {
let textContent:String!
textContent = textField.text
//3.Here we add '-' on overself.
let textWithHifen:NSString = "\(textContent)-"
textField.text = textWithHifen as String
dateFormate = false
}
}
//4. this one helps to make sure only 8 character is added in textfield .(ie: dd-mm-yy)
return newLength <= 8;
}
return true
}
That's it now user can enter their DOB.No need to worry about '-' it will be added automatically.
Swift 3:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
//1. To make sure that this is applicable to only particular textfield add tag.
if textField.tag == 1 {
//2. this one helps to make sure that user enters only numeric characters and '-' in fields
let numbersOnly = CharacterSet(charactersIn: "1234567890-")
let Validate = string.rangeOfCharacter(from: numbersOnly.inverted) == nil ? true : false
if !Validate {
return false;
}
if range.length + range.location > textField.text?.characters.count {
return false
}
let newLength = (textField.text?.characters.count)! + string.characters.count - range.length
if newLength == 3 || newLength == 6 {
let char = string.cString(using: NSUTF8StringEncoding)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
dateFormate = false;
}else{
dateFormate = true;
}
if dateFormate {
let textContent:String!
textContent = textField.text
//3.Here we add '-' on overself.
let textWithHifen:NSString = "\(textContent)-"
textField.text = textWithHifen as String
dateFormate = false
}
}
//4. this one helps to make sure only 8 character is added in textfield .(ie: dd-mm-yy)
return newLength <= 8;
}
return true
}
Swift5
// Use textfield delegate shouldChangeCharactersIn
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (textField.text?.count == 2) || (textField.text?.count == 5) {
if !(string == "") {
textField.text = (textField.text)! + "-"
}
}
return !(textField.text!.count > 7 && (string.count ) > range.length)
}
I have an iOS Xcode 7.3 Swift2 project I'm working on. It has different UITextFields that are limited to 3 digits, specifically only numbers. They are assigned to the UITextFieldDelegate and it's working well.
Here is where I limit them:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return true }
let newLength = text.characters.count + string.characters.count - range.length
let limitLength = 3
if newLength > limitLength {
return false
}
let numberOnly = NSCharacterSet.init(charactersInString: "0123456789")
let stringFromTextField = NSCharacterSet.init(charactersInString: string)
let strValid = numberOnly.isSupersetOfSet(stringFromTextField)
return strValid
}
However, some of the UITextFields need to be limited to numbers still AND also limited to a single digit, how can I institute this in the section above, only for those specific UITextFields?
The names of the UITextFields that need to be single digits are:
widthInches
lengthInches
I tried placing this after the first guard section with no luck:
guard let text2 = widthInches.text else { return true }
let newLength2 = text2.characters.count + string.characters.count - range.length
let limitLength2 = 3
if newLength2 > limitLength2 {
return false
}
You can also try this code for limit textfield
actually i am using here textfield tag. Because custom textfield.
If you using custom textfield like TextfieldEffect in this condition tag will help you for limit of Textfield.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool{
if textField.tag == txtCountryCode.tag{
let maxLength = 4
let currentString: NSString = textField.text!
let newString: NSString =
currentString.stringByReplacingCharactersInRange(range, withString: string)
return newString.length <= maxLength
}
if textField.tag == txtMobileNumber.tag{
let maxLength = 10
let currentString: NSString = textField.text!
let newString: NSString =
currentString.stringByReplacingCharactersInRange(range, withString: string)
return newString.length <= maxLength
}
return true
}
I hope this will help you.
The function shouldChangeCharactersInRange passes in the particular textField as one of its parameters. You can look at that and see if it points to the same instance as the ones you want to shorten, like this:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return true }
var limitLength = 3
if textField == widthInches || textField == lengthInches {
limitLength = 1
}
let newLength = text.characters.count + string.characters.count - range.length
if newLength > limitLength {
return false
}
let numberOnly = NSCharacterSet.init(charactersInString: "0123456789")
let stringFromTextField = NSCharacterSet.init(charactersInString: string)
let strValid = numberOnly.isSupersetOfSet(stringFromTextField)
return strValid
}
Assuming all other requirements are the same (numbers only) this will do the trick.
There are other ways, for example - you could subclass UITextField and add a limitLength field, then use that field in the delegate, but that's probably overkill for just 2 exceptions.
Hello in your func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool the textField param is the textField that has trigger this event so you can check with yours textfields objects and if are equal to one of them then make a different behavior
I hope this helps you,
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
return (textField.text?.utf16.count ?? 0) + string.utf16.count - range.length <= TEXT_FIELD_LIMIT
}
This counts the number of characters based on UTF-16 representation, as range.length is given in UTF-16 base. If you need to count the number of characters in other ways, the expression may get longer. If you want only numbers to be input use textField.keyboardType = UIKeyboardTypeDecimalPad . If you want specific textFields then add tags and compare them and if they are equal you can implement your specific code for that.
Check this link for detailed answer :
http://www.globalnerdy.com/2016/05/24/a-better-way-to-program-ios-text-fields-that-have-maximum-lengths-and-accept-or-reject-specific-characters/
update for swift 3 add this class and call it TextField.swift. it will add the limit input on the storyboard.
import UIKit
private var maxLengths = [UITextField: Int]()
extension UITextField {
#IBInspectable var maxLength: Int {
get {
guard let length = maxLengths[self] else {
return Int.max
}
return length
}
set {
maxLengths[self] = newValue
// Any text field with a set max length will call the limitLength
// method any time it's edited (i.e. when the user adds, removes,
// cuts, or pastes characters to/from the text field).
addTarget(
self,
action: #selector(limitLength),
for: UIControlEvents.editingChanged
)
}
}
func limitLength(textField: UITextField) {
guard let prospectiveText = textField.text,
prospectiveText.characters.count > maxLength else {
return
}
// If the change in the text field's contents will exceed its maximum
length,
// allow only the first [maxLength] characters of the resulting text.
let selection = selectedTextRange
// text = prospectiveText.substring(with:Range<String.Index>
(prospectiveText.startIndex ..< prospectiveText.index(after: maxLength))
let s = prospectiveText
// Get range 4 places from the start, and 6 from the end.
let c = s.characters;
let r = c.index(c.startIndex, offsetBy: 0)..<c.index(c.endIndex, offsetBy: maxLength - c.count)
text = s[r]
// Access the string by the range.
selectedTextRange = selection
}
}
or download here - >TextField.swift
I have 4 UItextfield for enter the top number. Like 1 2 3 4. When I enter the top number in my all text field, and if I am in last urtext field - and if I press backward button or x key in my key board - My number are in each text field are not getting deleted. I was not able to delete.
Here is my code :
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let value = textField.text!
let length = value.characters.count
if (length == 1) {
return false
}
if (textField == Field1) {
self.performSelector(Selector("setNextResponder:"), withObject: Field2, afterDelay: 0.2)
textField1 = string
} else if (textField == Field2) {
self.performSelector(Selector("setNextResponder:"), withObject: Field3, afterDelay: 0.2)
textField2 = string
} else if (textField == Field3) {
self.performSelector(Selector("setNextResponder:"), withObject: Field4, afterDelay: 0.2)
textField3 = string
} else if (textField == Field4) {
textField.resignFirstResponder()
textField4 = string
nextButton.enabled = true
}
else if (textField == Field4)
{
if string == "" && textField.text?.characters.count == 1 {
Field1.text = ""
Field2.text = ""
Field3.text = ""
Field4.text = ""
Field1.becomeFirstResponder()
}
}
return true
}
What i am missing?
You can make it like this:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if textField.text?.characters.count == 1 && string == "" {
if textField == txt2 {
txt2.text = ""
txt1.becomeFirstResponder()
} else if textField == txt3 {
txt3.text = ""
txt2.becomeFirstResponder()
} else if textField == txt4 {
txt4.text = ""
txt3.becomeFirstResponder()
}
}
return true
}
Still if possible you should create a separate button with clearText action to clear all textfield instead of clearing the textfield from the clear button. It will look as better UI/UX as per the default iOS clear button behaviour
Try :
func textFieldShouldClear(textField: UITextField) -> Bool {
textField.text = ""
textField.resignFirstResponder()
return false
}
Also choose an appropriate option from attribute inspector.