Limitar el número de caracteres en uitextview

80

Estoy dando una vista de texto para tuitear alguna cadena.

Estoy aplicando el siguiente método para restringir el número de caracteres a 140 de longitud.

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

El código funciona bien, excepto la primera condición de que el retroceso no funciona. Supongamos que he alcanzado el límite de 140 caracteres para que el método me dé falso y el usuario no pueda insertar más caracteres pero luego de eso cuando intento borrar algunos caracteres la vista de texto se comporta como si estuviera deshabilitada.

Entonces, la pregunta es: "¿Cómo eliminar caracteres textview.texto volver a habilitar la vista de texto?"

harshalb
fuente
Compruebe esta respuesta
Hemang

Respuestas:

67

En su lugar, debería buscar una cadena vacía, como dice la referencia de Apple

Si el usuario presiona la tecla Suprimir, la longitud del rango es 1 y un objeto de cadena vacía reemplaza ese único carácter.

Creo que la verificación que realmente desea hacer es algo así como [[textView text] length] - range.length + text.length > 140para tener en cuenta las operaciones de cortar / pegar.

David Gelhar
fuente
gracias pero puede ser más específico No puedo entender la especificación técnica de Apple
harshalb
solo dime qué debo poner en la primera condición. Estoy buscando esto durante casi 4 horas
harshalb
9
Creo que la verificación que realmente desea hacer es algo así como [[textView text] length] - range.length + text.length > 140, para tener en cuenta las operaciones de cortar / pegar.
David Gelhar
2
[[textView text] length] - range.length + text.length> 140 debe ser [[textView text] length] - range.length + text.length <140
Kuzon
Kuzon, no si devuelve verdadero como predeterminado y desea devolver falso si excede el límite de 140 caracteres.
piedra
165
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    return textView.text.length + (text.length - range.length) <= 140;
}

Esto tiene en cuenta que los usuarios cortan texto o eliminan cadenas de más de un carácter (es decir, si seleccionan y luego presionan la tecla de retroceso), o resaltan un rango y pegan cadenas más cortas o más largas que él.

Versión Swift 4.0

 func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    return textView.text.count + (text.count - range.length) <= 140
}
Tim
fuente
¿Es esto una IBAction? ¿Cómo lo conecto al TextView en cuestión cuando el usuario escribe?
alumno
1
Debe convertir su controlador de vista en un UITextViewDelegate y luego conectar al propietario del archivo como delegado de la vista de texto
Tim
Pensé que sería más justo hacer una pregunta de seguimiento: tengo problemas con tener dos UITextviews que necesitan límites de caracteres en el mismo controlador. ¿Podrías ayudarme? stackoverflow.com/questions/25272413/…
alumno
Esto debe marcarse como la respuesta correcta. Gracias
Hernan Arber
Esto provocará un bloqueo si pega un texto que es demasiado largo para caber (por falselo tanto , se devolverá) y luego intentará deshacer la acción.
Raimundas Sakalauskas
18

para 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
}
Rohit Sisodia
fuente
10

Sin embargo, también puede usar el siguiente código de trabajo.

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

    NSInteger restrictedLength=140;

    NSString *temp=textView.text;

    if([[textView text] length] > restrictedLength){
        textView.text=[temp substringToIndex:[temp length]-1];
    }
}
Saroj
fuente
Generalmente no es la forma preferida de editar algo después de que se ha configurado. Es mejor comprobar esto en "shouldChangeCharactersInRange" para evitar que se edite el texto.
Benjamin Piette
7

Con Swift 5 y iOS 12, pruebe la siguiente implementación del textView(_:shouldChangeTextIn:replacementText:)método que forma parte del UITextViewDelegateprotocolo:

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
}
  • La parte más importante de este código es la conversión de range( NSRange) a rangeOfTextToReplace( Range<String.Index>). Vea este video tutorial para comprender por qué esta conversión es importante.
  • Para que esto funcione correctamente el código, también se debe establecer el textField's smartInsertDeleteTypevalor a UITextSmartInsertDeleteType.no. Esto evitará la posible inserción de un espacio extra (no deseado) al realizar una operación de pegado.

El código de muestra completo a continuación muestra cómo implementar textView(_:shouldChangeTextIn:replacementText:)en un 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
    }

}
Imanou Petit
fuente
5

Rápido:

// 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;
}
Alexander Volkov
fuente
countElementsha sido reemplazado por counten swift 1.2
Tim Windsor Brown
1
y en Swift 2 tienes que textView.text.characters.count o cualquier codificación que quieras: developer.apple.com/swift/blog/?id=30
Heckscheibe
4

ue esto

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{

    int limit = 139;

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

}

esto solo ingresará 140 caracteres y puede eliminarlos si es necesario

B25 dic
fuente
4

¡Limite el desbordamiento, no el texto completo!

Al regresar falseen el ...shouldChangeTextInRange...método delegado, en realidad está limitando todo el texto y manejar las siguientes situaciones podría ser muy difícil:

  • Copiar y pegar
  • Seleccione un área del texto y edite
  • Usar sugerencia automática
  • Uso de entrada de voz (comando de voz o dictado)

Así que puedes:

Solo limita el desbordamiento del texto

Eliminando caracteres adicionales:

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

¡Puedes hacerlo incluso sobre la marcha ! poniendo este código dentro de la acción del textViewo textFieldcon el .editingChangedevento.

Mojtaba Hosseini
fuente
Colocar esto en el delegado de UITextView func textViewDidChange(_ textView: UITextView) {...}funciona maravillosamente, solo recortando el final de un texto largo pegado
Josselin
2

Aunque necesitaba una if-elsecondición, esto funcionó para mí:

- (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;
}

Inicialmente, el botón está desactivado. Pero si desea que el usuario no pueda publicar una prueba vacía, simplemente ponga una condición al hacer clic en el botón:

- (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
}
Vaibhav Saran
fuente
1

El problema con algunas de las respuestas dadas anteriormente es, por ejemplo, tengo un campo de texto y tengo que establecer un límite de entrada de 15 caracteres, luego se detiene después de ingresar el 15º carácter. pero no permiten borrar. Ese es el botón de eliminar que tampoco funciona. Ya que estaba enfrentando el mismo problema. Salió con la solución, dada a continuación. Funciona perfecto para mí

- (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;
 }
}

Tengo un campo de texto, cuya etiqueta he establecido "6" y he restringido el límite máximo de caracteres = 30; funciona bien en todos los casos

Jasmeet
fuente
1

Versión Swift de @Tim Gostony:

// 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;
}
Michael Shang
fuente
1

Aquí vamos para lograr el mejor ajuste. Muestra el número de caracteres restantes: quedan 'n' caracteres.

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
}
Ventilador YSR
fuente
1

Si también está buscando poder pegar código hasta el número máximo de caracteres, mientras corta el desbordamiento y actualiza una etiqueta de recuento:

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
}

Con la extensión:

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
    }
}
Daniel
fuente
1

Probar esto:-

 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
}
Abhijeet Mallick
fuente
0

Escriba el siguiente código en el textView:shouldChangeTextInRange:replacementText:método:

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

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
}
Gustiin
fuente
0

Utilice el siguiente código.

- (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;
    }
}
Vikas Grandhi
fuente
si se usa la condición para eliminar caracteres de la vista de texto
Vikas Grandhi
0

Aquí está la solución más simple para restringir que el usuario ingrese el número de caracteres en UITextFieldo UITextViewen iOS swift

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

Nota: aquí el límite puede ser cualquier cosa desde 1hasta nsegún su requisito, por ejemplo: si está trabajando en el número de teléfono, el limitvalor será 10 si desea aplicar el mismo en UITextViewsolo el método se cambiará y en el lugar textfielddonde se usarátextview

Vipul Dungranee_MI
fuente