UITextView en iOS7 ha sido muy raro. Como escribe y están entrando en la última línea de su UITextView, el desplazamiento de la vista no desplazarse a la parte inferior como se debe y que hace que el texto se «recortan». He tratado de establecer la clipsToBound propiedad que NO, pero aún clips el texto.

No quiero llamar «setContentOffset:animado» porque para uno: que es muy chapucero solución.. en segundo lugar: si el cursor en la mitad (verticalmente) de nuestro textview, que va a causar el desplazamiento no deseado.

Aquí está una captura de pantalla.

UITextView en iOS7 clips de la última línea de la cadena de texto

Cualquier ayuda sería muy apreciada!

Gracias!

  • Estoy experimentando el mismo problema en el dispositivo. Encontraste alguna solución para este problema? Gracias!
  • El potencial de duplicar. Mi respuesta es: stackoverflow.com/a/19200023/4397
  • posibles duplicados de UITextView cursor por debajo de marco al cambiar de frame
  • Lo siento por la respuesta tardía — me di por vencido en la búsqueda de una solución y se terminó el edificio, fuera de mi «en la vista texto» con un embedded web ver con el elemento textarea. No es mi solución ideal pero funciona :T.
  • Para mí, el problema persiste en iOS 7.0.3 tanto en el simulador y un dispositivo.
  • No hay ningún problema en 7.1, excepto la última línea está vacía. Y todas las soluciones no funcionan cuando la última línea está vacía. Así que no hay solución en iOS 7.1.
  • ¿Alguien tiene un fix para iOS 7.1?
  • El problema se CORRIGIÓ en iOS 8.

InformationsquelleAutor ryan | 2013-09-23

11 Comentarios

  1. 93

    El problema es debido a iOS 7. En la vista de texto delegado, agregue este código:

    - (void)textViewDidChange:(UITextView *)textView {
        CGRect line = [textView caretRectForPosition:
            textView.selectedTextRange.start];
        CGFloat overflow = line.origin.y + line.size.height
            - ( textView.contentOffset.y + textView.bounds.size.height
            - textView.contentInset.bottom - textView.contentInset.top );
        if ( overflow > 0 ) {
            //We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it)
            //Scroll caret to visible area
            CGPoint offset = textView.contentOffset;
            offset.y += overflow + 7; //leave 7 pixels margin
            //Cannot animate with setContentOffset:animated: or caret will not appear
            [UIView animateWithDuration:.2 animations:^{
                [textView setContentOffset:offset];
            }];
        }
    }
    
    • Por fin una solución que funciona! Me pasé varias horas sobre este tema hasta que encontré esta solución… muchas Gracias! Por CIERTO, alguna idea de si esto es un bug? No tengo este problema en anteriores versiones de iOS.
    • Muchas gracias! Espero que será corregido en futuras versiones de iOS.
    • GRAN TRABAJO el HOMBRE @ davidisdk
    • Funciona muy bien, gracias 😀 quieren que esto no era necesario.
    • Gracias jefe ! Funcionó !
    • No funciona en iOS 7.1 cuando la última línea está vacía. Pero cuando no está vacío no es el problema en absoluto.
    • Yo estaba como tú, nada de trabajo en iOS 7.1, hasta que he encontrado este : stackoverflow.com/a/19797795/1511646 (que espero que sea de ayuda 😉
    • user0000000, no me ayuda. Pero la siguiente ayuda: stackoverflow.com/questions/22315755/…
    • Maravilloso, exactamente lo que estaba buscando. Gracias.
    • Aquí está el MonoTouch versión de davididsk la más excelente solución (ver más abajo).

  2. 21

    La solución que he encontrado aquí era agregar una línea de revisión después de crear un UITextView:

    self.textview.layoutManager.allowsNonContiguousLayout = NO;
    

    Esta línea fija tres cuestiones tuve la creación de un UITextView basado en editor de código con resaltado de sintaxis en iOS7:

    1. Desplazamiento mantener el texto en la vista cuando la edición (el tema de este post)
    2. UITextView ocasionalmente saltando después de descartar el teclado
    3. UITextView al azar de desplazamiento salta al intentar desplazar la vista

    Nota, me hizo cambiar el tamaño de toda la UITextView cuando el teclado se muestra/oculta.

    • No ayuda con cualquier cosa.
    • Su relly obras Thks gmyers
    • «NO» es el valor predeterminado por el docs
    • realmente un gran trabajo contestar esta debe ser la mejor respuesta 🙂
    • Nada más trabajado para mí, excepto por este!! Muchas gracias. Gente, para los cuales no trabajo sólo puede tener otro problema.
    • gracias! realmente funciona!
    • «NO» es el valor predeterminado, pero de alguna manera funciona. Gracias.

  3. 6

    Trate de la aplicación de la -textViewDidChangeSelection: método delegado de la UITextViewDelegate como este:

    -(void)textViewDidChangeSelection:(UITextView *)textView {
        [textView scrollRangeToVisible:textView.selectedRange];
    }
    
  4. 2

    Heres una versión modificada de la respuesta seleccionada por davidisdk.

    - (void)textViewDidChange:(UITextView *)textView {
        NSRange selection = textView.selectedRange;
    
        if (selection.location + selection.length == [textView.text length]) {
            CGRect caretRect = [textView caretRectForPosition:textView.selectedTextRange.start];
            CGFloat overflow = caretRect.origin.y + caretRect.size.height - (textView.contentOffset.y + textView.bounds.size.height - textView.contentInset.bottom - textView.contentInset.top);
    
            if (overflow > 0.0f) {
                CGPoint offset = textView.contentOffset;
                offset.y += overflow + 7.0f;
    
                [UIView animateWithDuration:0.2f animations:^{
                    [textView setContentOffset:offset];
                }];
            }
        } else {
            [textView scrollRangeToVisible:selection];
        }
    }
    

    Me estaba poniendo un bug que cuando el textView del tamaño del contenido es mayor que el de los límites y el cursor está fuera de la pantalla (como el uso de un teclado y pulsando la tecla de flecha) el textView no animar a que el texto que se inserta.

    • No funciona en iOS 7.1 cuando la última línea está vacía. Pero cuando no está vacío no es el problema en absoluto. ¿Tienes un fix para iOS 7.1?
  5. 1

    Mi humilde opinión este es el respuesta definitiva para todos los de la típica UITextView de desplazamiento o el teclado en iOS 7. Limpio, fácil de leer, fácil de usar, fácil de mantener y puede ser fácilmente reutilizados.

    El truco elemental:
    Simplemente cambiar el tamaño de la UITextView, no el contenido del recuadro!

    He aquí un ejemplo práctico. Da por sentado que usted tiene un PLUMÍN/Guión-basado en el uso de UIViewController Autodiseño y la UITextView llena toda la raíz de la vista en el UIViewController. Si no, tendrá que adaptarse a cómo cambiar el textViewBottomSpaceConstraint a sus necesidades.

    Cómo:


    Agregar estas propiedades:

    @property (nonatomic, weak) IBOutlet NSLayoutConstraint *textViewBottomSpaceConstraint;
    @property (nonatomic) CGFloat textViewBottomSpaceConstraintFromNIB;
    

    Conecte el textViewBottomSpaceConstraint en el Interface Builder (no te olvides!)

    A continuación, en viewDidLoad:

    //Save the state of the UITextView's bottom constraint as set up in your NIB/Storyboard
    self.textViewBottomSpaceConstraintFromNIB = self.textViewBottomSpaceConstraint.constant;
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShowNotification:)
                                                 name:UIKeyboardWillShowNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHideNotification:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];
    

    Agregar estos métodos para manejar el Teclado de cambio de tamaño (gracias a https://github.com/brennanMKE/Interfaces/tree/master/Keyboarding – estos son los métodos por brennan!):

    - (void)keyboardWillShowNotification:(NSNotification *)notification {
        CGFloat height = [self getKeyboardHeight:notification forBeginning:TRUE];
        NSTimeInterval duration = [self getDuration:notification];
        UIViewAnimationOptions curve = [self getAnimationCurve:notification];
    
        [self keyboardWillShowWithHeight:height duration:duration curve:curve];
    }
    
    - (void)keyboardWillHideNotification:(NSNotification *)notification {
        CGFloat height = [self getKeyboardHeight:notification forBeginning:FALSE];
        NSTimeInterval duration = [self getDuration:notification];
        UIViewAnimationOptions curve = [self getAnimationCurve:notification];
    
        [self keyboardWillHideWithHeight:height duration:duration curve:curve];
    }
    
    - (NSTimeInterval)getDuration:(NSNotification *)notification {
        NSDictionary *info = [notification userInfo];
    
        NSTimeInterval duration;
    
        NSValue *durationValue = [info objectForKey:UIKeyboardAnimationDurationUserInfoKey];
        [durationValue getValue:&duration];
    
        return duration;
    }
    
    - (CGFloat)getKeyboardHeight:(NSNotification *)notification forBeginning:(BOOL)forBeginning {
        NSDictionary *info = [notification userInfo];
    
        CGFloat keyboardHeight;
    
        NSValue *boundsValue = nil;
        if (forBeginning) {
            boundsValue = [info valueForKey:UIKeyboardFrameBeginUserInfoKey];
        }
        else {
            boundsValue = [info valueForKey:UIKeyboardFrameEndUserInfoKey];
        }
    
        UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
        if (UIDeviceOrientationIsLandscape(orientation)) {
            keyboardHeight = [boundsValue CGRectValue].size.width;
        }
        else {
            keyboardHeight = [boundsValue CGRectValue].size.height;
        }
    
        return keyboardHeight;
    }
    
    - (UIViewAnimationOptions)getAnimationCurve:(NSNotification *)notification {
        UIViewAnimationCurve curve = [[notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
    
        switch (curve) {
            case UIViewAnimationCurveEaseInOut:
                return UIViewAnimationOptionCurveEaseInOut;
                break;
            case UIViewAnimationCurveEaseIn:
                return UIViewAnimationOptionCurveEaseIn;
                break;
            case UIViewAnimationCurveEaseOut:
                return UIViewAnimationOptionCurveEaseOut;
                break;
            case UIViewAnimationCurveLinear:
                return UIViewAnimationOptionCurveLinear;
                break;
        }
    
        return kNilOptions;
    }
    

    Por último, agregar estos métodos para reaccionar a las notificaciones del teclado y cambiar el tamaño de la UITextView

    - (void)keyboardWillShowWithHeight:(CGFloat)height duration:(CGFloat)duration curve:(UIViewAnimationOptions)curve
    {
        CGFloat correctionMargin = 15; //you can experiment with this margin so the bottom text view line is not flush against the keyboard which doesn't look nice
        self.textViewBottomSpaceConstraint.constant = height + correctionMargin;
    
        [self.view setNeedsUpdateConstraints];
    
        [UIView animateWithDuration:duration delay:0 options:curve animations:^{
            [self.view layoutIfNeeded];
        } completion:^(BOOL finished) {
    
        }];
    }
    
    - (void)keyboardWillHideWithHeight:(CGFloat)height duration:(CGFloat)duration curve:(UIViewAnimationOptions)curve
    {
        self.textViewBottomSpaceConstraint.constant = self.textViewBottomSpaceConstraintFromNIB;
    
        [self.view setNeedsUpdateConstraints];
    
        [UIView animateWithDuration:duration delay:0 options:curve animations:^{
            [self.view layoutIfNeeded];
        } completion:^(BOOL finished) {
    
        }];
    }
    

    También agregar estos métodos para desplazarse automáticamente a donde el usuario hizo clic

    - (void)textViewDidBeginEditing:(UITextView *)textView
    {
        [textView scrollRangeToVisible:textView.selectedRange];
    }
    
    - (void)textViewDidChangeSelection:(UITextView *)textView
    {
        [textView scrollRangeToVisible:textView.selectedRange];
    }
    
  6. 0
    textView.contentInset = UIEdgeInsetsMake(0.0, 0.0, 10.0, 0.0);
    

    Esto también va a abordar el problema

  7. 0

    Si usted está utilizando el StoryBoard, a continuación, este comportamiento también puede ocurrir si usted deja Autodiseño en (como es por defecto) y no superior/inferior de restricciones para su UITextView. Compruebe el Archivo de Inspector para ver lo que su diseño Automático de estado es…

  8. 0

    Aquí es el MonoTouch versión de davididsk la más excelente solución (desde arriba).

    TextView.SelectionChanged += (object sender, EventArgs e) => {
                    TextView.ScrollRangeToVisible(TextView.SelectedRange);
                };
    
    
                TextView.Changed += (object sender, EventArgs e) => {
    
                    CGRect line = TextView.GetCaretRectForPosition(TextView.SelectedTextRange.Start);
                    nfloat overflow = line.Y + line.Height - 
                                         (TextView.ContentOffset.Y + 
                                          TextView.Bounds.Height -          
                                          TextView.ContentInset.Bottom -
                                          TextView.ContentInset.Top );
                    if ( overflow > 0 ) 
                    {
                        //We are at the bottom of the visible text and introduced 
                        //a line feed, scroll down (iOS 7 does not do it)
                        //Scroll caret to visible area
                        CGPoint offset = TextView.ContentOffset;
                        offset.Y+= overflow + 7; //leave 7 pixels margin
                        //Cannot animate with setContentOffset:animated: 
                        //or caret will not appear
                        UIView.Animate(0.1,()=> {
                            TextView.ContentOffset = offset;
                        });
                    }
                };
    
  9. 0

    Esta línea hace que la última línea de texto para no mostrar por mí:

    textView.scrollEnabled = false
    

    Pruebe a quitar esto y a ver qué pasa…

  10. -1
       textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    

    Esta resuelto el problema, para mí

    • No ayuda para mí.
    • esto deshabilita el diseño automático…
    • Esto no es lo que el autor quiere lograr. Y como @Softlion mencionado esto deshabilita el diseño automático.
  11. -2

    Conjunto theViewDelegate a «sí mismo» en su .m y utilizar en su .h, a continuación, agregue este código .m

    Se ocupará TANTO de las versiones de este fallo que se están produciendo para ir a la siguiente línea con el texto (envoltura o retorno de carro) y escribiendo… Y va a la siguiente línea con sólo un retorno de carro y no escribir (este código, a diferencia de otros del código, se desplaza para mostrar el cursor parpadeante, no recortados en este segundo fallo escenario)

    //!!!*!!****!*!**!*!*!!!MAKE SURE YOU SET DELEGATE AND USE THE <UITEXTVIEWDELEGATE>
    
    -(void)textViewDidChange:(UITextView *)textView {
        [theTextView scrollRangeToVisible:[textView selectedRange]];//resizing textView frame causes text itself "content frame?" to still go below the textview frame and get clipped... auto-scrolling must be implimented. (iOS7 bug)
    }
    
    -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
        if (([text isEqualToString:@"\n"]) && (range.location == textView.text.length)) {//"return" at end of textView
            [textView scrollRectToVisible:CGRectMake(5,5,5,999999999999999999) animated:NO];//for some reason the textViewDidChange auto scrolling doesnt work with a carriage return at the end of your textView... so I manually set it INSANELY low (NOT ANIMATED) here so that it automagically bounces back to the proper position before interface refreshes when textViewDidChange is called after this.
        }
        return YES;
    }
    
    • Es difícil tomar el código en serio cuando contiene algo como CGRectMake(5,5,5,999999999999999999).
    • es sólo scrollToBottom. Yo podría haberle dicho a importar <float.h> y en lugar de utilizar DBL_MAX pero pensé que sería demasiado de un molestia, así que sólo he difundido 9, el efecto es el mismo.

Dejar respuesta

Please enter your comment!
Please enter your name here