uitextview ios7

UITextView en iOS7 recorta la última línea de texto



(11)

Aquí está la versión MonoTouch de la solución más excelente de davididsk (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; }); } };

UITextView en iOS7 ha sido realmente extraño. A medida que escribe y está ingresando la última línea de su UITextView, la vista de desplazamiento no se desplaza hacia abajo como debería y hace que el texto sea "recortado". He intentado configurar su propiedad clipsToBound en NO, pero aún se recorta el texto.

No quiero llamar a "setContentOffset: animated" porque para uno: esa es una solución muy hacky ... en segundo lugar: si el cursor estaba en el medio (verticalmente) de nuestra vista de texto, provocará un desplazamiento no deseado.

Aquí hay una captura de pantalla.

¡Cualquier ayuda sería muy apreciada!

¡Gracias!


Aquí está 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]; } }

Estaba obteniendo un error que cuando el tamaño del contenido de TextView es más grande que los límites y el cursor está fuera de la pantalla (como usar un teclado y presionar la tecla de flecha) la vista de texto no se anima al texto que se está insertando.


El problema se debe a iOS 7. En el delegado de vista de texto, 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]; }]; } }


Esta es la respuesta definitiva para todos los problemas típicos de UITextView-scrolling / keyboard en iOS 7. Es limpio, fácil de leer, fácil de usar, fácil de mantener y puede reutilizarse fácilmente.

El truco básico: simplemente cambie el tamaño de UITextView, ¡no el recuadro de contenido!

Aquí hay un ejemplo práctico. Da por descontado que tiene un UIBiewController basado en NIB / Storyboard usando Autolayout y el UITextView rellena toda la vista raíz en el UIViewController. De lo contrario, deberá adaptar la forma en que modifique textViewBottomSpaceConstraint según sus necesidades.

Cómo:

Agregue estas propiedades:

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

Conecte el textViewBottomSpaceConstraint en Interface Builder (¡ no lo olvide! )

Luego 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];

Agregue estos métodos para manejar el cambio de tamaño del teclado (gracias a https://github.com/brennanMKE/Interfaces/tree/master/Keyboarding - ¡estos métodos son 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; }

Finalmente, agregue estos métodos para reaccionar a las notificaciones del teclado y cambiar el tamaño del 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 agregue estos métodos para desplazarse automáticamente al lugar donde hizo clic el usuario

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


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

textView.scrollEnabled = false

Intenta eliminar esto y ve lo que sucede ...


Intente implementar el método -textViewDidChangeSelection: delegar desde UITextViewDelegate de la siguiente manera:

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


La solución que encontré here fue agregar una corrección de una línea después de crear un UITextView:

self.textview.layoutManager.allowsNonContiguousLayout = NO;

Esta línea solucionó tres problemas que tuve al crear un editor de código basado en UITextView con resaltado de sintaxis en iOS7:

  1. Desplazamiento para mantener el texto a la vista al editar (el problema de esta publicación)
  2. UITextView salta ocasionalmente después de cerrar el teclado
  3. El desplazamiento aleatorio UITextView salta al intentar desplazar la vista

Tenga en cuenta que cambié el tamaño de toda la UITextView cuando se muestra / oculta el teclado.


Si está utilizando StoryBoard, este comportamiento también puede ocurrir si dejó AutoLayout activado (como lo hace de manera predeterminada) y no configuró restricciones superiores / inferiores para su UITextView. Compruebe el Inspector de archivos para ver cuál es su estado de AutoLayout ...


Establezca ViewDelegate en "self" en su .m y utilícelo en su .h y luego agregue este código a su .m

Manejará AMBAS las versiones de este problema que están ocurriendo para ir a la siguiente línea con texto (envoltura o retorno de carro) y escribir ... Y yendo a la siguiente línea con solo un retorno de carro y sin escribir (este código, a diferencia del otro código, se desplazará para mostrar que el cursor parpadeante no está recortado en este segundo escenario de falla)

//!!!*!!****!*!**!*!*!!!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; }


textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

Esto resolvió el problema para mí


textView.contentInset = UIEdgeInsetsMake(0.0, 0.0, 10.0, 0.0);

Esto también abordará su problema