iphone - ¿Cómo puedo hacer que un desplazamiento UIScrollView a la posición del cursor de una UITextView?
cocoa-touch (3)
¡Qué bueno que encontraste mi publicación al respecto, me alegro de que haya sido útil!
Creo que es posible que no esté viendo el resultado final debido a esta línea:
CGRect finalRect = CGRectMake(1, scrollHeight, 1, 1);
Está creando un cuadro de 1x1 punto. Una sola línea de texto puede tener una altura de 20 o 30 puntos (dependiendo del tamaño de la fuente). Entonces, si está desplazando este punto a visible, puede que solo muestre el píxel superior de la línea inferior, lo que hace que la línea inferior sea efectivamente invisible. Si haces el finalRect un poco más alto para que cubra toda la línea, podría funcionar mejor:
CGRect finalRect = CGRectMake(1, scrollHeight, 1, 30);
Además, puede estar llamando a su código scrollRectToVisible varias veces a la vez, lo que puede causar "vibraciones". En mi código, solo ejecuto scrollRectToVisible desde textViewDidChangeSelection y cambio el tamaño de UITextView (si es necesario) en textViewDidChange. UIScrollView (y por herencia UITableView) tiene soporte integrado para desplazar el elemento seleccionado activamente para que sea visible, lo que en mis pruebas funcionó bien al simplemente redimensionar el UITextView mientras tipeaba (pero no al seleccionar un punto específico dentro con un toque).
Tengo una vista que es similar a la aplicación de notas, es decir, escribir en un pedazo de papel rayado. Para hacer que el texto y el documento se desplacen simultáneamente, desactivé el desplazamiento de UITextView y, en su lugar, coloqué mi UITextView y mi UIImageView dentro de UIScrollView.
El único problema con esto es que, cuando el usuario escribe, el texto desaparece debajo del teclado, porque obviamente el UIScrollView no sabe desplazarse a la posición del cursor.
¿Hay alguna manera simple de recuperar la posición del cursor y decirle a UIScrollView que se desplace allí?
---EDITAR---
A partir de algo similar aquí (donde alguien intentaba hacer algo similar con una UITableView), he logrado hacer una UITextView cada vez más editable con un fondo fijo que casi se desplaza perfectamente. Los únicos problemas ahora son:
- Hay una ligera sacudida a medida que el texto avanza si el usuario escribe particularmente rápido.
- Si el usuario oculta el teclado, selecciona texto en la parte inferior de la pantalla y vuelve a mostrar el teclado, debe escribir un par de letras antes de volver a ser visible: no se desplaza hacia arriba inmediatamente.
- Cuando el usuario oculta el teclado, la animación como el marco de la vista de desplazamiento llena la pantalla no se siente del todo bien de alguna manera.
Aquí está el código: estaría muy agradecido si alguien puede refinarlo más ...
#import "NoteEditViewController.h"
#import "RLWideLabelTableCell.h"
@implementation NoteEditViewController
@synthesize keyboardSize;
@synthesize keyboardHideDuration;
@synthesize scrollView;
@synthesize noteTextView;
//
// Dealloc and all that stuff
//
- (void)loadView
{
[super loadView];
UIScrollView *aScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.scrollView = aScrollView; [aScrollView release];
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, noteTextView.frame.size.height);
[self.view addSubview:scrollView];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Get notified when keyboard is shown. Don''t need notification when hidden because we are
// using textViewDidEndEditing so we can start animating before the keyboard disappears.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
// Add the Done button so we can test dismissal of the keyboard
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(doneButton:)];
self.navigationItem.rightBarButtonItem = doneButton; [doneButton release];
// Add the background image that will scroll with the text
CGRect noteImageFrame = CGRectMake(self.view.bounds.origin.x,
noteTitleImageFrame.size.height,
self.view.bounds.size.width, 500);
UIView *backgroundPattern = [[UIView alloc] initWithFrame:noteImageFrame];
backgroundPattern.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Notepaper-iPhone-Line"]];
[self.scrollView addSubview:backgroundPattern];
[self.view sendSubviewToBack:backgroundPattern];
[backgroundPattern release];
// Add the textView
CGRect textViewFrame = CGRectMake(noteImageFrame.origin.x+27,
noteImageFrame.origin.y-3,
noteImageFrame.size.width-35,
noteImageFrame.size.height);
RLTextView *textView = [[RLTextView alloc] initWithFrame:textViewFrame];
self.noteTextView = textView; [textView release];
self.noteTextView.font = [UIFont fontWithName:@"Cochin" size:21];
self.noteTextView.backgroundColor = [UIColor clearColor];
self.noteTextView.delegate = self;
self.noteTextView.scrollEnabled = NO;
[self.scrollView addSubview:self.noteTextView];
}
- (void)doneButton:(id)sender
{
[self.view endEditing:TRUE];
}
// When the keyboard is shown, the UIScrollView''s frame shrinks so that it fits in the
// remaining space
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
float kbHideDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
self.keyboardHideDuration = kbHideDuration;
self.keyboardSize = kbSize;
self.scrollView.frame = CGRectMake(self.view.bounds.origin.x,
self.view.bounds.origin.y,
self.view.bounds.size.width,
self.view.bounds.size.height - kbSize.height);
}
// When the user presses ''done'' the UIScrollView expands to the size of its superview
// again, as the keyboard disappears.
- (void)textViewDidEndEditing:(UITextView *)textView
{
[UIScrollView animateWithDuration:keyboardHideDuration animations:^{self.scrollView.frame = self.view.bounds;}];
}
// This method needs to get called whenever there is a change of cursor position in the text box
// That means both textViewDidChange: and textViewDidChangeSelection:
- (void)scrollToCursor
{
// if there is a selection cursor…
if(noteTextView.selectedRange.location != NSNotFound) {
NSLog(@"selectedRange: %d %d", noteTextView.selectedRange.location, noteTextView.selectedRange.length);
// work out how big the text view would be if the text only went up to the cursor
NSRange range;
range.location = noteTextView.selectedRange.location;
range.length = noteTextView.text.length - range.location;
NSString *string = [noteTextView.text stringByReplacingCharactersInRange:range withString:@""];
CGSize size = [string sizeWithFont:noteTextView.font constrainedToSize:noteTextView.bounds.size lineBreakMode:UILineBreakModeWordWrap];
// work out where that position would be relative to the textView''s frame
CGRect viewRect = noteTextView.frame;
int scrollHeight = viewRect.origin.y + size.height;
CGRect finalRect = CGRectMake(1, scrollHeight, 1, 1);
// scroll to it
[self.scrollView scrollRectToVisible:finalRect animated:YES];
}
}
// Whenever the text changes, the textView''s size is updated (so it grows as more text
// is added), and it also scrolls to the cursor.
- (void)textViewDidChange:(UITextView *)textView
{
noteTextView.frame = CGRectMake(noteTextView.frame.origin.x,
noteTextView.frame.origin.y,
noteTextView.frame.size.width,
noteTextView.contentSize.height);
self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width,
noteTextView.frame.size.height+200);
[self scrollToCursor];
}
// The textView scrolls to the cursor whenever the user changes the selection point.
- (void)textViewDidChangeSelection:(UITextView *)aTextView
{
[self scrollToCursor];
}
// PROBLEM - the textView does not scroll until the user starts typing - just selecting
// it is not enough.
- (void)textViewDidBeginEditing:(UITextView *)textView
{
[self scrollToCursor];
}
No es estrictamente una respuesta a su pregunta, pero este es un enfoque diferente del truco de fondo de notas: http://www.cocoanetics.com/2010/03/stuff-you-learn-from-reverse-engineering-notes-app/
Lo he usado y funciona bien.
No hay una manera fácil de encontrar las coordenadas de pantalla para cualquier texto o cursor en una UITextView
.
Lo que debe hacer es registrarse en UIKeyboardWillShowNotification
y UIKeyboardWillShowNotification
. Y en las devoluciones de llamadas, usted ajusta el size
o contentInsets
de UIScrollView
para ajustar el tamaño del teclado.
El tamaño del teclado, e incluso la duración de la animación se proporciona en las notificaciones userInfo
, por lo que puede hacerlo de una manera animada agradable.
Aquí encontrará más información y código de muestra: http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html