I am trying to prevent users from entering the characters '#' and empty spaces (' '). I have got as far as below (see code below) but not sure how to complete the rest ...
class CreateTags: UIViewController, UITextFieldDelegate {
/*** OUTLETS ***/
#IBOutlet weak var inputTxtOutlet: UITextField!
override func viewDidLoad() {
self.inputTxtOutlet.delegate = self
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return true
}
}
You need o implement following delegate method (as you already implemented)
Set delegate
yourtextField.delegate = self
Delegate method
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string == "#" || string == " " {
return false //disallow # and a space
}
return true
}
In another way you can do it as follow
Create a constant that contains disallowed chars.
let disallowedChars = ["#", " "] //add more chars as per your need
In delegate method check those chars...
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if disallowedChars.contains(string) {
return false
}
return true
}
Try to be specific for UITextfields!
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if textField == inputTxtOutlet {
let myCharSet = CharacterSet(charactersIn:" #")
let output: String = string.trimmingCharacters(in: myCharSet.inverted)
let isValid: Bool = (string == output)
if isValid {
return false
} else {
return true
}
}
return true
}
let restrictedChars = ["#", "*", " "]
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return restrictedChars.contains(string) ? false : true
}
Here is a one-liner. (Works for copy paste!)
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return !string.contains(where: {$0 == "#" || $0 == " "})
}
If you have a lot of restricted characters,
let restrictedCharacters: [Character] = [" ", "#", "?"]
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return !(Set(string).intersection(Set(restrictedCharacters)).count > 0)
}
Here is your solution:-
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let characters = ["#", "$", "!", "&","#"]
for character in characters{
if string == character{
print("This characters are not allowed")
return false
}
}
}
uses this How to restrict certain characters in UITextField in Swift? example
extension String {
var containsValidCharacter: Bool {
guard self != "" else { return true }
let hexSet = CharacterSet(charactersIn: "1234567890ABCDEFabcdef")
let newSet = CharacterSet(charactersIn: self)
return hexSet.isSuperset(of: newSet)
}
}
You use it like with the UITextFieldDelegate.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return (string.containsValidCharacter)
}
Replace Your "shouldChangeCharactersIn" method with below code
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let characters = ["#", " "]
for character in characters{
if string == character{
print("This characters are not allowed")
return false
}
}
return true
}
Related
So I have a UIViewRepresentable which wraps a UITextField, and I get this error during the textFieldshouldChangeCharactersInRange method:
struct MyTextField: UIViewRepresentable {
class Coordinator: NSObject, UITextFieldDelegate, ObservableObject {
#Binding var text: String
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let currentValue = textField.text as NSString? {
let proposedValue = currentValue.replacingCharacters(in: range, with: string)
text = proposedValue // Warning is thrown from here
}
return true
}
}
...
What's the correct way to update the binding here without triggering this warning?
Update on next even loop, like
DispatchQueue.main.async {
text = proposedValue
}
I am using Xcode 8 and Swift 3. I am creating an app for iOS. How will I make inputted lowercase letters be automatically converted to uppercase letters in the text field and vice-versa?
The first answer is OK but with some modifications. Tested on letters with diacritical marks. Tested with copy and paste text methods.
The following that says
class ViewController: UIViewController {
must be like this.
class ViewController: UIViewController, UITextFieldDelegate {
This applies only to one text field only. To force inputting in uppercase even when Shift key is locked or pressed down...
#IBOutlet weak var textField: UITextField!
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.lowercased() == string {
textField.text = (textField.text! as NSString).replacingCharacters(in: range, with: string.uppercased())
} else {
textField.text = (textField.text! as NSString).replacingCharacters(in: range, with: string.uppercased())
}
return false
}
Do not forget to insert the following inside "override func viewDidLoad()".
textField.delegate = self
This applies to one text field only. To force inputting in lowercase even when Shift key is locked or pressed down...
#IBOutlet weak var textField: UITextField!
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.lowercased() == string {
textField.text = (textField.text! as NSString).replacingCharacters(in: range, with: string.lowercased())
} else {
textField.text = (textField.text! as NSString).replacingCharacters(in: range, with: string.lowercased())
}
return false
}
Do not forget to insert the following inside "override func viewDidLoad()".
textField.delegate = self
The following is for two text fields. Assuming one text field is always uppercase and the other one is always lowercase.
#IBOutlet weak var textFieldAlwaysUppercase: UITextField!
#IBOutlet weak var textFieldAlwaysLowercase: UITextField!
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField.isEqual(textFieldAlwaysUppercase) {
textFieldAlwaysUppercase.text = (textField.text! as NSString).replacingCharacters(in: range, with: string.uppercased())
return false
} else if textField.isEqual(textFieldAlwaysLowercase) {
textFieldAlwaysLowercase.text = (textField.text! as NSString).replacingCharacters(in: range, with: string.lowercased())
return false
}
return true
}
Do not forget to insert the following inside "override func viewDidLoad()".
textFieldAlwaysUppercase.delegate = self
textFieldAlwaysLowercase.delegate = self
I'm using Xcode 8 and Swift 3.
I have a project with 3 textfields, 1 button to clear and label to display result.
Inside my class ViewController I have:
class ViewController: UIViewController,UITextFieldDelegate {
#IBOutlet weak var input1: UITextField!
#IBOutlet weak var input2: UITextField!
#IBOutlet weak var input3: UITextField!
#IBOutlet weak var lblResult: UILabel!
#IBOutlet weak var clearButton: UIButton!
I want to limit my textfields inputs to max 3 digits but also to a value of 360. I manage to get code for both things and they work if used only one at a time but because they both start with func textfield I can't make them both work together. Do I have to do it in different class?
I know this is a basic question but its part of the learning process.
These are the two codes I want to combine:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool
{
let maxLength = 3
let currentString: NSString = textField.text! as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
return newString.length <= maxLength
}
and:
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool
{
var startString = ""
if (textField.text != nil)
{
startString += textField.text!
}
startString += string
let limitNumber = Int(startString)
if limitNumber! > 360
{
return false
}
else
{
return true;
}
}
They are both inside the class ViewController.
Thanks for the help!
If I am not mistaken, here is all you need:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
let maxLength = 3
let limitValue = 360
let text = textField.text!
let currentString: NSString = text as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
var startString = ""
if !text.isEmpty {
startString += text
}
startString += string
let limitNumber = Int(startString)!
return limitNumber < limitValue && newString.length <= maxLength
}
Update:
Auto focus on a next texfield.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
let maxLength = 3
let limitValue = 360
let text = textField.text!
let currentString: NSString = text as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
var startString = ""
if !text.isEmpty {
startString += text
}
startString += string
let limitNumber = Int(startString)!
let newLength: Int = newString.length
if textField == input1 {
if newLength == maxLength {
input2.becomeFirstResponder()
}
}
if textField == input2 {
if newLength == maxLength {
input3.becomeFirstResponder()
}
}
if textField == input3 {
if newLength == maxLength {
self.view.endEditing(true)
}
}
return limitNumber < limitValue && newLength <= maxLength
}
You need to add an if statement in func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool checking for the current textFieldlike this:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textFiled == input1 {
// do logic for input1
} else if textFiled == input2 {
// do logic for input2
}
}
Swift switch statement will do it.
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool
{
switch textField {
case input1:
// ...
case input2:
// ...
case input3:
// ...
default:
break
}
}
People didn't understood the question. Actually, all you need is merging your statement as mentioned by javimuu.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool
{
let maxLength = 3
let currentString: NSString = textField.text! as NSString
let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
var startString = ""
if (textField.text != nil)
{
startString += textField.text!
}
startString += string
let limitNumber = Int(startString)
return newString.length <= maxLength && limitNumber! <= 360
}
I'd like to set a maximum number of characters allowed to be typed both in a UITextView and a UITextField. This number will be then shown in a little label (for user's reference, Twitter Style.)
Update Swift 4.X
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
let numberOfChars = newText.count
return numberOfChars < 10 // 10 Limit Value
}
Try this out:
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
let newText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)
let numberOfChars = newText.characters.count // for Swift use count(newText)
return numberOfChars < 10;
}
SWIFT 4
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
return newText.count < 10
}
Swift 4:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
return newText.count <= 70
}
Try this out:-
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
print("chars \(textView.text.characters.count) \( text)")
if(textView.text.characters.count > 20 && range.length == 0) {
print("Please summarize in 20 characters or less")
return false;
}
return true;
}
Swift 3.0
Just override this UITextFieldDelegate function, set the desired characterLimit variable and you are good to go:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
{
let characterLimit = 5
let newText = NSString(string: textField.text!).replacingCharacters(in: range, with: string)
let numberOfChars = newText.characters.count
return numberOfChars < characterLimit
}
Swift 4/ Xcode 9.1
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let currentText = textView.text ?? ""
guard let stringRange = Range(range, in: currentText) else { return false }
let changedText = currentText.replacingCharacters(in: stringRange, with: text)
return changedText.count <= 399 // Pass your character count here
}
Swift 4 , Xcode 9.1 GM
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
return textView.text.count + (text.count - range.length) <= 200
}
Swift 5
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
var newText = textView.text!
newText.removeAll { (character) -> Bool in
return character == " " || character == "\n"
}
return (newText.count + text.count) <= 40
}
Adding support of pasting text with cutting it by a maxLength + avoiding UNDO action crash:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if let maxLength = maxLength {
let maxReplacementLength = min(range.length, maxLength - range.location)
let replacementRange = NSRange(location: range.location, length: maxReplacementLength)
let result = NSString(string: (textView.text ?? "")).replacingCharacters(in: replacementRange, with: text)
if result.count <= maxLength && range.length <= maxLength - range.location {
return true
}
textView.text = String(result[..<result.index(result.startIndex, offsetBy: min(result.count, maxLength))])
return false
}
return true
}
Update for Swift 5
Gives the most forward result
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
return range.location < 140 // limit to 140 chars
}
I'm creating a login system and I don't want spaces to be allowed in the username field. Instead of check and validating the field, I want to prevent spaces from being added.
So, every time the user presses the spacebar, nothing should happen. How can I do that?
I've seen Instagram do this.
This is my code so far:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var signUp: UIBarButtonItem!
#IBOutlet weak var navBar: UINavigationBar!
#IBOutlet weak var UsernameText: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.clipsToBounds = true
UsernameText.attributedPlaceholder = NSAttributedString(string:"TypeYourUsername",
attributes:[NSForegroundColorAttributeName: UIColor.whiteColor()])
func textField(UsernameText: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if (string == " ") {
return false
}
return true
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
UsernameText.becomeFirstResponder()
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
Yes you can do it. Override UITextField delegate method shouldChangeCharactersInRange. And in that method check for space character. If found than return false.
Note: Don't forget to set delegate for textfield.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if (string == " ") {
return false
}
return true
}
Edit: More Code
class ViewController : UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField : UITextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if (string == " ") {
return false
}
return true
}
}
Here textField object is an IBOutlet. It means that text field control is in storyboard and connected with this variable.
Swift 4.1/4.2/5.0/5.1/5.2
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string == " " {
return false
}
return true
}
In Swift 2.0
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let whitespaceSet = NSCharacterSet.whitespaceCharacterSet()
let range = string.rangeOfCharacterFromSet(whitespaceSet)
if let _ = range {
return false
}
else {
return true
}
}
In Swift 2.1
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let whitespaceSet = NSCharacterSet.whitespaceCharacterSet()
if let _ = string.rangeOfCharacterFromSet(whitespaceSet) {
return false
}
return true
}
Swift 3
class SignUpViewController: UIViewController, UITextFieldDelegate {
lazy var emailTextField: UITextField = {
let tf = UITextField()
tf.translatesAutoresizingMaskIntoConstraints = false
tf.placeholder = "Email address"
tf.delegate = self
return tf
}()
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let whitespaceSet = NSCharacterSet.whitespaces
if let _ = string.rangeOfCharacter(from: whitespaceSet) {
return false
}
else {
return true
}
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let whitespaceSet = CharacterSet.whitespaces
if let _ = string.rangeOfCharacter(from: whitespaceSet) {
return false
} else {
return true
}
}
Swift 5
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return string != " "
}
This is the most easy to understand syntax for me.
Swift 4.1
Just simple with Single line of code you can stop whitespace
For All Textfield
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
textField.text = textField.text?.replacingOccurrences(of: " ", with: "")
return true
}
For Single Textfield
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if textField == txtid
{
textField.text = textField.text?.replacingOccurrences(of: " ", with: "")
}
return true
}
Here you can disable WhiteSpaces until Your (First character )text enter. (some improvement )
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let whitespaceSet = NSCharacterSet.whitespaces
let range = string.rangeOfCharacter(from: whitespaceSet)
if let _ = range {
let text = textField.text ?? ""
if text.isBlankByTrimming || text.isEmpty {
return false
}else {
return true
}
}
else {
return true
}
}
Here u can use this Extension to trim white spaces .(even when u are checking your validations )
using above textfield Delegate you can disable whitespaces but if have string like this
Example : "MyName Surname "
so can trim end spaces also before saving this data.
extension String {
var isBlankByTrimming: Bool {
let trimmed = self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
return trimmed.isEmpty
}
func trimWhitespacesAndNewlines() -> String{
return self.trimmingCharacters(in:
CharacterSet.whitespacesAndNewlines)
}
}
for use ::
let yourString = "MyName Surname "
let finalString = yourString.trimWhitespacesAndNewlines()
You can check if the User tapped on space key and neglect it with the following logic. But I think you cannot disable the button itself.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
string != " "
}