¿Cómo puedo hacer que un UITextField suba cuando el teclado está presente al comenzar a editar?
Con el SDK de iOS:
Tengo un UIView
with UITextField
s que abre un teclado. Lo necesito para poder:
Permitir el desplazamiento del contenido de
UIScrollView
para ver los otros campos de texto una vez que se abre el teclado"Saltar" automáticamente (desplazándose hacia arriba) o acortando
Sé que necesito un UIScrollView
. Intenté cambiar la clase de my UIView
a UIScrollView
, pero todavía no puedo desplazar los cuadros de texto hacia arriba o hacia abajo.
¿Necesito tanto a UIView
como a UIScrollView
? ¿Uno va dentro del otro?
¿Qué se debe implementar para desplazarse automáticamente al campo de texto activo?
Idealmente, la mayor parte posible de la configuración de los componentes se realizará en Interface Builder. Me gustaría escribir código solo para lo que lo necesita.
Nota: el UIView
(o UIScrollView
) con el que estoy trabajando aparece mediante una barra de pestañas ( UITabBar
), que debe funcionar normalmente.
Estoy agregando la barra de desplazamiento solo para cuando aparece el teclado. Aunque no es necesario, creo que proporciona una mejor interfaz porque el usuario puede desplazarse y cambiar cuadros de texto, por ejemplo.
Lo tengo funcionando donde cambio el tamaño del marco UIScrollView
cuando el teclado sube y baja. Simplemente estoy usando:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
//Keyboard becomes visible
scrollView.frame = CGRectMake(scrollView.frame.origin.x,
scrollView.frame.origin.y,
scrollView.frame.size.width,
scrollView.frame.size.height - 215 + 50); // Resize
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
// Keyboard will hide
scrollView.frame = CGRectMake(scrollView.frame.origin.x,
scrollView.frame.origin.y,
scrollView.frame.size.width,
scrollView.frame.size.height + 215 - 50); // Resize
}
Sin embargo, esto no "sube" ni centra automáticamente los campos de texto inferiores en el área visible, que es lo que realmente me gustaría.
Sólo necesitarás un
ScrollView
si el contenido que tienes ahora no cabe en la pantalla del iPhone. (Si está agregandoScrollView
como supervisión de los componentes solo para hacer elTextField
desplazamiento hacia arriba cuando aparece el teclado, entonces no es necesario).La forma estándar de evitar
TextField
que el teclado cubra los mensajes de correo electrónico es mover la vista hacia arriba o hacia abajo cada vez que se muestra el teclado.
Aquí hay un código de muestra:
#define kOFFSET_FOR_KEYBOARD 80.0
-(void)keyboardWillShow {
// Animate the current view out of the way
if (self.view.frame.origin.y >= 0)
{
[self setViewMovedUp:YES];
}
else if (self.view.frame.origin.y < 0)
{
[self setViewMovedUp:NO];
}
}
-(void)keyboardWillHide {
if (self.view.frame.origin.y >= 0)
{
[self setViewMovedUp:YES];
}
else if (self.view.frame.origin.y < 0)
{
[self setViewMovedUp:NO];
}
}
-(void)textFieldDidBeginEditing:(UITextField *)sender
{
if ([sender isEqual:mailTf])
{
//move the main view, so that the keyboard does not hide it.
if (self.view.frame.origin.y >= 0)
{
[self setViewMovedUp:YES];
}
}
}
//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3]; // if you want to slide up the view
CGRect rect = self.view.frame;
if (movedUp)
{
// 1. move the view's origin up so that the text field that will be hidden come above the keyboard
// 2. increase the size of the view so that the area behind the keyboard is covered up.
rect.origin.y -= kOFFSET_FOR_KEYBOARD;
rect.size.height += kOFFSET_FOR_KEYBOARD;
}
else
{
// revert back to the normal state.
rect.origin.y += kOFFSET_FOR_KEYBOARD;
rect.size.height -= kOFFSET_FOR_KEYBOARD;
}
self.view.frame = rect;
[UIView commitAnimations];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
También estaba teniendo muchos problemas con la UIScrollView
composición de varios archivos UITextFields
, de los cuales uno o más quedaban ocultos por el teclado cuando se estaban editando.
Aquí hay algunas cosas a considerar si UIScrollView
no se desplaza correctamente.
1) Asegúrese de que su tamaño de contenido sea mayor que el UIScrollView
tamaño del marco. La forma de entenderlo UIScrollViews
es que UIScrollView
es como una ventana de visualización del contenido definido en contentSize. Entonces, para que se UIScrollview
desplace a cualquier lugar, contentSize debe ser mayor que UIScrollView
. De lo contrario, no es necesario desplazarse ya que todo lo definido en contentSize ya está visible. Por cierto, tamaño de contenido predeterminado = CGSizeZero
.
2) Ahora que comprende que UIScrollView
en realidad es una ventana a su "contenido", la forma de asegurarse de que el teclado no oscurezca su UIScrollView's
"ventana" de visualización sería cambiar el tamaño UIScrollView
de manera que cuando el teclado esté presente, tenga la UIScrollView
ventana. dimensionado solo al UIScrollView
frame.size.height original menos la altura del teclado. Esto asegurará que su ventana sea solo esa pequeña área visible.
3) Aquí está el problema: cuando implementé esto por primera vez, pensé que tendría que obtener el CGRect
campo de texto editado y llamar al UIScrollView's
método scrollRecToVisible. Implementé el UITextFieldDelegate
método textFieldDidBeginEditing
con la llamada al scrollRecToVisible
método. En realidad, esto funcionó con un efecto secundario extraño: el desplazamiento lo colocaríaUITextField
en su posición. Durante mucho tiempo no pude entender qué era. Luego comenté el textFieldDidBeginEditing
método Delegado y ¡¡todo funciona!!(???). Al final resultó que, creo que en UIScrollView
realidad implícitamente trae implícitamente lo editado actualmente UITextField
a la ventana visible. Mi implementación del UITextFieldDelegate
método y la posterior llamada al scrollRecToVisible
fue redundante y fue la causa del extraño efecto secundario.
Estos son los pasos para desplazarse correctamente hacia su UITextField
lugar UIScrollView
cuando aparezca el teclado.
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:self.view.window];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:self.view.window];
keyboardIsShown = NO;
//make contentSize bigger than your scrollSize (you will need to figure out for your own use case)
CGSize scrollContentSize = CGSizeMake(320, 345);
self.scrollView.contentSize = scrollContentSize;
}
- (void)keyboardWillHide:(NSNotification *)n
{
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// resize the scrollview
CGRect viewFrame = self.scrollView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.size.height += (keyboardSize.height - kTabBarHeight);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[self.scrollView setFrame:viewFrame];
[UIView commitAnimations];
keyboardIsShown = NO;
}
- (void)keyboardWillShow:(NSNotification *)n
{
// This is an ivar I'm using to ensure that we do not do the frame size adjustment on the `UIScrollView` if the keyboard is already shown. This can happen if the user, after fixing editing a `UITextField`, scrolls the resized `UIScrollView` to another `UITextField` and attempts to edit the next `UITextField`. If we were to resize the `UIScrollView` again, it would be disastrous. NOTE: The keyboard notification will fire even when the keyboard is already shown.
if (keyboardIsShown) {
return;
}
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// resize the noteView
CGRect viewFrame = self.scrollView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.size.height -= (keyboardSize.height - kTabBarHeight);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[self.scrollView setFrame:viewFrame];
[UIView commitAnimations];
keyboardIsShown = YES;
}
- Regístrese para recibir notificaciones del teclado en
viewDidLoad
- Cancelar el registro para recibir notificaciones del teclado en
viewDidUnload
- Asegúrese de que
contentSize
esté configurado y sea mayor que suUIScrollView
enviewDidLoad
- Reducir el
UIScrollView
cuando el teclado está presente - Revertir cuando
UIScrollView
el teclado desaparezca. - Utilice un ivar para detectar si el teclado ya se muestra en la pantalla, ya que las notificaciones del teclado se envían cada vez que se
UITextField
tabula, incluso si el teclado ya está presente para evitar reducirloUIScrollView
cuando ya está reducido .
Una cosa a tener en cuenta es que se UIKeyboardWillShowNotification
activará incluso cuando el teclado ya esté en la pantalla cuando presione otra tecla UITextField
. Me encargué de esto usando un ivar para evitar cambiar el tamaño UIScrollView
cuando el teclado ya está en la pantalla. ¡Cambiar el tamaño sin querer UIScrollView
cuando el teclado ya está ahí sería desastroso!
Espero que este código les ahorre muchos dolores de cabeza a algunos de ustedes.
En realidad, es mejor utilizar la implementación de Apple, como se proporciona en los documentos . Sin embargo, el código que proporcionan es defectuoso. Reemplace la parte que se encuentra keyboardWasShown:
justo debajo de los comentarios por la siguiente:
NSDictionary* info = [aNotification userInfo];
CGRect keyPadFrame=[[UIApplication sharedApplication].keyWindow convertRect:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] fromView:self.view];
CGSize kbSize =keyPadFrame.size;
CGRect activeRect=[self.view convertRect:activeField.frame fromView:activeField.superview];
CGRect aRect = self.view.bounds;
aRect.size.height -= (kbSize.height);
CGPoint origin = activeRect.origin;
origin.y -= backScrollView.contentOffset.y;
if (!CGRectContainsPoint(aRect, origin)) {
CGPoint scrollPoint = CGPointMake(0.0,CGRectGetMaxY(activeRect)-(aRect.size.height));
[backScrollView setContentOffset:scrollPoint animated:YES];
}
Los problemas con el código de Apple son los siguientes: (1) Siempre calculan si el punto está dentro del marco de la vista, pero es un ScrollView
, por lo que es posible que ya se haya desplazado y debes tener en cuenta ese desplazamiento:
origin.y -= scrollView.contentOffset.y
(2) Cambian el contentOffset por la altura del teclado, pero queremos lo contrario (queremos cambiar contentOffset
por la altura que es visible en la pantalla, no lo que no lo es):
activeField.frame.origin.y-(aRect.size.height)
In textFieldDidBeginEditting
y in textFieldDidEndEditing
llaman a la función [self animateTextField:textField up:YES]
así:
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField:textField up:YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField:textField up:NO];
}
-(void)animateTextField:(UITextField*)textField up:(BOOL)up
{
const int movementDistance = -130; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? movementDistance : -movementDistance);
[UIView beginAnimations: @"animateTextField" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
Espero que este código te ayude.
veloz 5
func animateTextField(textField: UITextField, up: Bool) {
let movementDistance: CGFloat = -130
let movementDuration: Double = 0.3
var movement:CGFloat = 0
if up {
movement = movementDistance
} else {
movement = -movementDistance
}
UIView.animate(withDuration: movementDuration, delay: 0, options: [.beginFromCurrentState]) {
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
animateTextField(textField: textField, up: true)
}
func textFieldDidEndEditing(_ textField: UITextField) {
animateTextField(textField: textField, up: false)
}
Simplemente usando TextFields:
1a) Usando Interface Builder
: Seleccionar todos los campos de texto => Editar => Incrustar en => ScrollView
1b) Incrustar manualmente TextFields en UIScrollView llamado scrollView
2) establecerUITextFieldDelegate
3) Configure cada textField.delegate = self;
(o haga conexiones en Interface Builder
)
4) Copiar/Pegar:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
CGPoint scrollPoint = CGPointMake(0, textField.frame.origin.y);
[scrollView setContentOffset:scrollPoint animated:YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
[scrollView setContentOffset:CGPointZero animated:YES];
}