How can I set characters remaining on a UILabel for the UITextView?
I have done this for the UITextField, but the same code does not work..
This is what I have tried:
func textView(textView: UITextView, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
if string == ""
{
if plainTextView.text!.characters.count == 0
{
charCount = 0
countLabel.text = String(format: "%i Characters Left", maxLength - charCount)
return false
}
charCount = (plainTextView.text!.characters.count - 1)
countLabel.text = String(format: "%i Characters Left", maxLength - charCount)
return true
}
else
{
charCount = (plainTextView.text!.characters.count + 1)
countLabel.text = String(format: "%i Characters Left", maxLength - charCount)
if charCount >= maxLength + 1
{
charCount = maxLength
countLabel.text = String(format: "%i Characters Left", maxLength - charCount)
return false;
}
}
return true
}
Any suggestions?
try this
import UIKit
class ViewController: UITextViewDelegate {
let maxLenghth = 200
func textViewDidChange(_ textView: UITextView) {
countLabel.text = "\(maxLength - textView.text.count)"
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
return textView.text.count + (text.count - range.length) <= maxLength
}
}
Swift 5
extension AddProperty2ViewController: UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
p_summary_line_textview.text = "\(5000 - textView.text.count)"
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
return textView.text.count + (text.count - range.length) <= 5000
}
}
func textViewDidBeginEditing(_ textView: UITextView) {
shrinkText()
}
func textViewDidChange(_ textView: UITextView) {
shrinkText()
}
func textViewDidEndEditing(_ textView: UITextView) {
shrinkText()
}
func shrinkText() {
sendButton.isEnabled = reviewTextField.text == "" ? false : true
var text = ""
var counter = 0
if reviewTextField.text.count > limit {
reviewTextField.text.forEach {
if counter < limit {
counter += 1
text.append($0)
} else {
return
}
}
reviewTextField.text = text
}
counterLabel.text = "\(reviewTextField.text.count) / \(limit)"
}
Related
How do I programmatically add a suffix ("kr") to an UITextView?
Thanks!
I assume this is when the user is typing to indicate a currency value.
In viewDidLoad assign your textview delegate (or wherever you wish to assign the delegate):
override func viewDidLoad() {
super.viewDidLoad()
myTextView.delegate = self
}
And then to add the suffix to the textview when user is typing
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if string.characters.count > 0 {
amountTypedString += string
let newString = amountTypedString + "kr"
myTextView.text = newString
} else {
amountTypedString = String(amountTypedString.characters.dropLast())
if amountTypedString.characters.count > 0 {
let newString = amountTypedString + "kr"
myTextView.text = newString
} else {
myTextView.text = "0kr"
}
}
return false
}
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'm trying to put in placeholders into my UITextViews, and found a solution here using this chunk of code:
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
let currentText:NSString = storyView.text
let updatedText = currentText.stringByReplacingCharactersInRange(range, withString:text)
if updatedText.isEmpty {
storyView.text = "Write out your story here!"
storyView.textColor = UIColor.lightGrayColor()
storyView.selectedTextRange = storyView.textRangeFromPosition(storyView.beginningOfDocument, toPosition: storyView.beginningOfDocument)
return false
}else if storyView.textColor == UIColor.lightGrayColor() && !text.isEmpty {
storyView.text = nil
storyView.textColor = UIColor.blackColor()
}
return true
}
func textViewDidChangeSelection(storyView: UITextView) {
if self.view.window != nil {
if storyView.textColor == UIColor.lightGrayColor() {
storyView.selectedTextRange = storyView.textRangeFromPosition(storyView.beginningOfDocument, toPosition: storyView.beginningOfDocument)
}
}
}
It works, and I'm happy with it, but I'd like to apply it to other UITextViews in the same ViewController. How would I do it without creating a duplicate instance of the textView method?
You can use textField.tag in your shouldChangeTextInRange method.
Give tag to your textField of same viewcontroller. And use that tag into shouldChangeTextInRange method.
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
let currentText:NSString = storyView.text
let updatedText = currentText.stringByReplacingCharactersInRange(range, withString:text)
if updatedText.isEmpty {
if (textField.tag==0)//
{
storyView.text = "Write out your story here!" // stuff
}
else if(textField.tag==1)//
{
storyView.text = "Example 2 "// stuff
}
storyView.textColor = UIColor.lightGrayColor()
storyView.selectedTextRange = storyView.textRangeFromPosition(storyView.beginningOfDocument, toPosition: storyView.beginningOfDocument)
return false
}else if storyView.textColor == UIColor.lightGrayColor() && !text.isEmpty {
storyView.text = nil
storyView.textColor = UIColor.blackColor()
}
return true
}
func textViewDidChangeSelection(storyView: UITextView) {
if self.view.window != nil {
if storyView.textColor == UIColor.lightGrayColor() {
storyView.selectedTextRange = storyView.textRangeFromPosition(storyView.beginningOfDocument, toPosition: storyView.beginningOfDocument)
}
}
}
May be it will help you.
I have followed this tutorial on how to restrict textField to a certain length and character set.
Here is my code, and yet the delegate isn't called:
VC class: this is called (verified while debugging)
var textManager = TextManager()
#IBOutlet weak var enterName_text: UITextField!
func onVideDidLoad() {
...
enterName_text.placeholder = StringConstans.name
enterName_text.delegate = textManager
}
TextManager class:
import Foundation
public class TextManager: NSObject, UITextFieldDelegate {
public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if string.characters.count == 0 {
return true
}
let currentText = textField.text ?? ""
let prospectiveText = (currentText as NSString).stringByReplacingCharactersInRange(range, withString: string)
return prospectiveText.containsOnlyCharactersIn("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") &&
prospectiveText.characters.count <= 6
}
}
The code below works. How does yours differ?
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
let textManager = TextManager()
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = textManager
}
}
public class TextManager: NSObject, UITextFieldDelegate {
public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
print("should")
if string.characters.count == 0 {
return true
}
let currentText = textField.text ?? ""
let prospectiveText = (currentText as NSString).stringByReplacingCharactersInRange(range, withString: string)
return prospectiveText.containsOnlyCharactersIn("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") &&
prospectiveText.characters.count <= 6
}
}
extension String {
func containsOnlyCharactersIn(matchCharacters: String) -> Bool {
let disallowedCharacterSet = NSCharacterSet(charactersInString: matchCharacters).invertedSet
return self.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
}
}
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
}