2011-06-04 19 views
13

En el contexto de la iPhone:UIKit: UIScrollView desplazándose automáticamente cuando un subvista aumenta su anchura más allá del borde de la pantalla

Tengo un UIScrollView que contiene un UIImage. Cuando el usuario toca la pantalla dentro del UIImage, se agrega un UITextField donde tocó el usuario. El usuario puede editar este UITextField, y el campo de texto se redimensionará automáticamente en función de si el texto fue agregado o eliminado.

Cuando el UITextField que se está editando aumenta su ancho, la vista de desplazamiento se desplaza automáticamente para mostrar el ancho incrementado.

El problema viene porque el desplazamiento automático del campo de texto no respeta el valor de y de la pantalla

Por ejemplo, dicen que el usuario añade un campo de texto en la parte inferior de la imagen. Cuando vayan a editar ese campo de texto, se mostrará el teclado, ocultando el campo de texto. Tengo un código en su lugar para desplazar la pantalla y mostrar el campo de texto. El problema aparece cuando el usuario ingresa tanto texto que ese campo de texto se extiende más allá del borde de la pantalla. Cuando esto sucede, la pantalla se desplaza horizontalmente para ajustarse al texto más ancho, pero también verticalmente: el desplazamiento vertical termina ocultando el campo de texto, anulando básicamente todo lo que hice para mostrar el campo de texto.

Código para mostrar el campo de texto si está oculto por el teclado:

- (void)keyboardWasShown:(NSNotification*)notification 
{ 
    NSDictionary* info = [notification userInfo]; 
    CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; 

    self.offset = self.contentOffset; 

    CGRect frame = self.frame; 
    // self.activeField is the name of the field that is the current first responder - this just adds a little bit of padding 
    frame.size.height -= keyboardSize.height + (self.activeField.frame.size.height * 2); 

    if (!CGRectContainsPoint(frame, self.activeField.frame.origin)) { 
     CGPoint scrollPoint = CGPointMake(self.offset.x, self.activeField.frame.origin.y - keyboardSize.height + (activeField.frame.size.height * 2)); 
    [self setContentOffset:scrollPoint animated:YES]; 
    } 
} 

Este es el código para aumentar el tamaño del campo de texto:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 
{ 
    NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string]; 
    CGSize stringSize = [string sizeWithFont:textField.font]; 
    CGSize newSize = [newString sizeWithFont:textField.font]; 

    // Make textField wider if we're close to running up against it 
    if (newSize.width > (textField.frame.size.width - self.widthOffset)) { 
     CGRect textFieldFrame = textField.frame; 
     if (stringSize.width > self.widthOffset) { 
      textFieldFrame.size.width += stringSize.width; 
     } 
     textFieldFrame.size.width += self.widthOffset; 
     textField.frame = textFieldFrame; 
    } 

    // Shrink the textField if there is too much wasted space 
    if ((textField.frame.size.width - newSize.width) > self.widthOffset) { 
     CGRect textFieldFrame = textField.frame; 
     textFieldFrame.size.width = newSize.width + self.widthOffset; 
     textField.frame = textFieldFrame; 
    } 
    return YES; 
} 

La pregunta es: ¿Cómo ¿Obtengo que UIScrollView respeta el valor y de sí mismo cuando se desplaza automáticamente?

+2

Awesome question! – Legolas

+0

Ayudaría si puede proporcionar un enlace con un proyecto de muestra. –

Respuesta

0

En lugar de cambiar el desplazamiento de contenido, cambie el marco de visualización de la vista de desplazamiento.

- (void)keyboardWill:(NSNotification*)notification 
{ 
    CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; 
    // Update the scroll view's frame to the region not covered by the keyboard. 
    self.frame = CGRectMake(self.fullSizedFrame.origin.x, 
          self.fullSizedFrame.origin.y, 
          self.fullSizedFrame.size.width, 
          self.fullSizedFrame.size.height - keyboardSize.height); 
} 

- (void)keyboardWillHide:(NSNotification*)notification 
{ 
    // Set the frame back to the original frame before the keyboard was shown. 
    self.frame = self.fullSizedFrame; 
} 

Si usted no permite al usuario cambiar la orientación de la pantalla, a continuación, fullSizedFrame podría fijarse a la estructura original de la vista cuando se muestra por primera vez. Si se permiten cambios en la orientación, deberá calcular el valor apropiado para fullSizedFrame en función de la orientación.

+0

Esto no funcionó. Ya estoy compensando la altura del marco de UIScrollView por la altura del teclado. –

5

Básicamente setFrame de UIScrollView reajustará el desplazamiento de la vista de desplazamiento, hecho por _adjustContentOffsetIfNecessary. Como ese método es privado y no está documentado, hay muy poco que podamos adivinar sobre cómo ocurrirá el ajuste. Hay dos formas de detener el desplazamiento innecesario o la compensación incorrecta configurada:

1) restablecer el desplazamiento UIScrollView después de aplicar setFrame. Esto puede hacerlo, si está modificando el marco de UIScrollView intencionalmente en función de algunos cálculos.

CGPoint oldOffset = [scrollView contentOffset];   
scrollView.frame = CGRectMake(newFrame); 
[scrollView setContentOffset:oldOffset];   

2) aplicar cambios de desplazamiento sin animación. En su keyboardWasShown, cambiar [self setContentOffset:scrollPoint animated:YES]; to
[self setContentOffset:scrollPoint animated:NO];

Motivo: cuando más de una corrección se realiza con la animación en adelante, el resultado desplazamiento es ambigua. Aquí el método interno (_adjustContentOffsetIfNecessary) aplica un cambio de desplazamiento y el otro lo hace su código.Se puede notar esto si intenta iniciar sesión todos los desplazamientos que se aplican en el método delegado UIScrollView:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView 
{ 
    NSLog(@" offset: %@", NSStringFromCGPoint(scrollView.conentOffset)) 
} 

que me haga saber si esto ayuda.

+0

@Hooray Im Helping ayudó la sugerencia? Si no, por favor actualice – Tatvamasi

+0

Disculpe por el largo tiempo de respuesta. Esto no lo resolvió. Anulé los métodos setContentOffset y tenía una declaración de inicio de sesión dentro de ellos: no se los llamaba, lo que parece indicar que es una clase principal que realiza el desplazamiento. –

2

Una posible solución podría ser responder al scrollViewDidScroll método delegado comprobar para ver si el UITextField está oculto de nuevo, luego volver a desplazarse si es necesario. Parece un truco, pero parece que el comportamiento de desplazamiento automático UIScrollView es lo que se interpone en su camino, y si no hay forma de afectarlo directamente, la única opción es evitarlo. También existe la desventaja, sin embargo, de que si haces esto, parece que se desplaza dos veces.

Si el comportamiento de desplazamiento automático ocurre solo cuando el UITextField se expande más allá del borde de la pantalla, también puede mover el campo para permanecer completamente visible si parece que va a expandirse más allá del borde de la pantalla.

+0

Si se trata de eso, recurriré a un truco como este, pero preferiría no hacerlo. +1 para una buena respuesta de todos modos. –

Cuestiones relacionadas