Limit number of characters in uitextview
IosIphoneUitextviewUitextviewdelegateIos 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
) torangeOfTextToReplace
(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
'ssmartInsertDeleteType
value toUITextSmartInsertDeleteType.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