Limit number of characters in uitextview

IosIphoneUitextviewUitextviewdelegate

Ios Problem Overview


I am giving a text view to tweet some string .

I am applying the following method to restrict the number of characters to 140 in length.

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
   return [[textView text] length] <= 140;
}

The code is working nicely except the first condition that backspace is not working. suppose that I have reached the limit of 140 characters so that the method will give me false and the user can not insert more characters but after that when I try to delete some characters the text view behave as it is disabled .

So the question is: "How to delete characters from textview.text or re-enable the text view?"

Ios Solutions


Solution 1 - Ios

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    return textView.text.length + (text.length - range.length) <= 140;
}

This accounts for users cutting text, or deleting strings longer than a single character (ie if they select and then hit backspace), or highlighting a range and pasting strings shorter or longer than it.

Swift 4.0 Version

 func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    return textView.text.count + (text.count - range.length) <= 140
}

Solution 2 - Ios

You should be looking for an empty string instead, as the apple reference says

> If the user presses the Delete key, the length of the range is 1 and an empty string object replaces that single character.

I think the check you actually want to make is something like [[textView text] length] - range.length + text.length > 140, to account for cut/paste operations.

Solution 3 - Ios

for swift 4:

//MARK:- TextView Delegate
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    //300 chars restriction
    return textView.text.count + (text.count - range.length) <= 300
}

Solution 4 - Ios

However you can use below working code also..

- (void)textViewDidChange:(UITextView *)textView{

    NSInteger restrictedLength=140;
    
    NSString *temp=textView.text;
    
    if([[textView text] length] > restrictedLength){
        textView.text=[temp substringToIndex:[temp length]-1];
    }
}

Solution 5 - Ios

 Limit the overflow, not the entire text!

By returning false in the ...shouldChangeTextInRange... delegate method, you are actually limiting the entire text and handling the following situations could be so hard:

  • Copy and pasting
  • Select an area of the text and edit
  • Using auto-suggest
  • Using voice input (voice command or dictation)

So you can:

Just limit the text-overflow!

By removing extra characters:

textView.text = String(textView.text.prefix(140))

You can do it even on the fly! by putting this code inside the action of the textView or textField with the .editingChanged event.

Solution 6 - Ios

With Swift 5 and iOS 12, try the following implementation of textView(_:shouldChangeTextIn:replacementText:) method that is part of the UITextViewDelegate protocol:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    guard let rangeOfTextToReplace = Range(range, in: textView.text) else {
        return false
    }
    let substringToReplace = textView.text[rangeOfTextToReplace]
    let count = textView.text.count - substringToReplace.count + text.count
    return count <= 10
}
  • The most important part of this code is the conversion from range (NSRange) to rangeOfTextToReplace (Range<String.Index>). See this video tutorial to understand why this conversion is important.
  • To make this code work properly, you should also set the textField's smartInsertDeleteType value to UITextSmartInsertDeleteType.no. This will prevent the possible insertion of an (unwanted) extra space when performing a paste operation.

The complete sample code below shows how to implement textView(_:shouldChangeTextIn:replacementText:) in a UIViewController:

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

    @IBOutlet var textView: UITextView! // Link this to a UITextView in Storyboard

    override func viewDidLoad() {
        super.viewDidLoad()

        textView.smartInsertDeleteType = UITextSmartInsertDeleteType.no
        textView.delegate = self
    }

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        guard let rangeOfTextToReplace = Range(range, in: textView.text) else {
            return false
        }
        let substringToReplace = textView.text[rangeOfTextToReplace]
        let count = textView.text.count - substringToReplace.count + text.count
        return count <= 10
    }

}

Solution 7 - Ios

Swift:

// MARK: UITextViewDelegate

let COMMENTS_LIMIT = 255
    
func textView(textView: UITextView,  shouldChangeTextInRange range:NSRange, replacementText text:String ) -> Bool {
    return count(comments.text) + (count(text) - range.length) <= COMMENTS_LIMIT;
}

Solution 8 - Ios

ue this

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    
    int limit = 139;

    return !([textField.text length]>limit && [string length] > range.length);
    
}

this will only enter 140 char and you can delete them if need

Solution 9 - Ios

Though I needed an if-else condition, so this worked for me:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    BOOL status = textView.text.length + (text.length - range.length) <= 15;
    if (status)
    {
        [self.btnShare setEnabled:YES];
        [self.btnShare setAlpha:1];
    }
    else
    {
        [self.btnShare setEnabled:NO];
        [self.btnShare setAlpha:0.25];
    }
    return status;
}

Intially the button is set to disabled. But if you want user cant post an empty test, simply put a condition on button click:

- (void)btnShare_click:(id)sender
{
    NSString *txt = [self.txtShare.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    if ([txt length] == 0)
    {
        [self.btnShare setEnabled:NO];
        [self.btnShare setAlpha:0.25f];
        [[[UIAlertView alloc]initWithTitle:nil message:@"Please enter some text to share." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
        return;
    }
    .
    .
    .
    .
    .
    .
    // rest of your code
}

Solution 10 - Ios

The Problem with some of the answer given above is, For example I have a text field and I have to set a limit of 15 characters input, then it stops after entering 15th Character. but they Don't allow to delete. That is the delete button also don't work. As I was facing the same problem. Came out with the solution , Given Below. Works Perfect for Me

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
 if(textField.tag==6)
 {
    if ([textField.text length]<=30)
    {
        return YES;   
    }
    else if([@"" isEqualToString:string])
    {
        textField.text=[textField.text substringToIndex:30 ];
    }
    
    return NO;
 }
 else
 {
    return YES;
 }
}

I am having a text field, whose tag I have set "6" and I have restricted the max char limit = 30 ; works fine in every case

Solution 11 - Ios

@Tim Gostony 's Swift Version:

// restrict the input for textview to 500
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    return count(textView.text) + (count(text) - range.length) <= 500;
}

Solution 12 - Ios

Here we go for best fit. Display number of characters left: 'n' characters left.

var charCount = 0;
let maxLength = 150
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    
    if text == "" // Checking backspace
    {
        if textView.text.characters.count == 0
        {
            charCount = 0
            characterCount.text = String(format: "%i Characters Left", maxLength - charCount)
            return false
        }
        charCount = (textView.text.characters.count - 1)
        characterCount.text = String(format: "%i Characters Left", maxLength - charCount)
      return true
    }
    else
    {
        charCount = (textView.text.characters.count + 1)
        characterCount.text = String(format: "%i Characters Left", maxLength - charCount)
        
        if charCount >= maxLength + 1
        {
            charCount = maxLength
            characterCount.text = String(format: "%i Characters Left", maxLength - charCount)
            return false;
        }
    }
    return true
}

Solution 13 - Ios

Try this out:-

 func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    print("chars \(textView.text.count) \( text)")

    if(textView.text.count > 20 && range.length == 0) {
        print("Please summarize in 20 characters or less")
        return false
    }
    return true
}

Solution 14 - Ios

If you're also looking to be able to paste code up to the max character count, while cutting off overflow, and updating a count label:

let maxChar: Int
let countLabel: UILabel

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    let oldChar = textView.text.count - range.length
    let oldRemainingChar = maxChar - oldChar
    let newChar = oldChar + text.count
    let newRemainingChar = maxChar - newChar
    let replaceChar = newRemainingChar > 0 ? text.count : oldRemainingChar
    
    if
        let textRange = textView.textRange(for: range),
        replaceChar > 0 || range.length > 0
    {
        textView.replace(textRange, withText: String(text.prefix(replaceChar)))
        countLabel.text = String(describing: maxChar - textView.text.count)
    }
    
    return false
}

With the extension:

extension UITextInput {
    func textRange(for range: NSRange) -> UITextRange? {
        var result: UITextRange?
    
        if
            let start = position(from: beginningOfDocument, offset: range.location),
            let end = position(from: start, offset: range.length)
        {
            result = textRange(from: start, to: end)
        
        }
    
        return result
    }
}

Solution 15 - Ios

Write below code in textView:shouldChangeTextInRange:replacementText: method :

if ([textView.text length]>=3 && ![text isEqualToString:@""]) {
    return NO;
}
return YES;

Solution 16 - Ios

Use the following code.

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    if(text.length == 0)
    {
        return YES;
    }
    else if(self.txtViewComments.text.length > 255)
    {
        return NO;
    }
    else
    {
        return YES;
    }
}

Solution 17 - Ios

Swift5:

let maxChars = 255

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
  if maxChars - aTextView.text.count == 0 {
    if range.length != 1 {
    return false
    }
  }
  return true
}

Solution 18 - Ios

Here is the simplest solution for restricting user to enter number of character in UITextField or in UITextView in iOS swift

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool 
{
   return textField.text!.count < limit ? true : false
}

Note: here limit can be anything from 1 to n as per your requirement, for e.g: if you working on phone number than limit value will be 10 if you want to apply same on UITextView just method will be change and at the place of textfield you will be use textview

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionharshalbView Question on Stackoverflow
Solution 1 - IosTimView Answer on Stackoverflow
Solution 2 - IosDavid GelharView Answer on Stackoverflow
Solution 3 - IosRohit SisodiaView Answer on Stackoverflow
Solution 4 - IosSarojView Answer on Stackoverflow
Solution 5 - IosMojtaba HosseiniView Answer on Stackoverflow
Solution 6 - IosImanou PetitView Answer on Stackoverflow
Solution 7 - IosAlexander VolkovView Answer on Stackoverflow
Solution 8 - IosB25DecView Answer on Stackoverflow
Solution 9 - IosVaibhav SaranView Answer on Stackoverflow
Solution 10 - IosJasmeetView Answer on Stackoverflow
Solution 11 - IosMichael ShangView Answer on Stackoverflow
Solution 12 - IosYSR fanView Answer on Stackoverflow
Solution 13 - IosAbhijeet MallickView Answer on Stackoverflow
Solution 14 - IosDanielView Answer on Stackoverflow
Solution 15 - Iosuser2493047View Answer on Stackoverflow
Solution 16 - IosVikas GrandhiView Answer on Stackoverflow
Solution 17 - IosGustinView Answer on Stackoverflow
Solution 18 - IosVipul Dungranee_MIView Answer on Stackoverflow