Objective C – Focus UITextField con scorrimento UIScrollView e visualizzazione Tastiera

Se state sviluppando un’applicazione iPhone in cui ci saranno da riempire dei campi, magari all’interno di un pannello scrollabile, dovrete sicuramente affrontare il fatto che il framework non vi aiuta con i focus dei TextField e lo scorrimento della View negli eventi di visualizzazione della tastiera.
Infatti dovrete manualmente ridimensionare la ScrollView facendola scorrere in maniera tale da rendere visibile il TextField che stiamo modificando.

Di seguito il sorgente (con commenti) che ho inserito nella mia applicazione, tale codice è stato sviluppato per firmware fino alla versione di iOS 6.1.
Vi faccio nota del fatto di aver effettuato l’estensione di una UIScrollView con l’aggiunta del protocollo UITextFieldDelegate. E’ necessario inserire dei tag sequenziali ai TextField in modo da sapere l’ordine in cui effettuare il focus, inoltre settate come delegato la stessa ScrollView in modo da attivare gli eventi di inizio e fine modifica dei TextField.

@interface LFBoxScroll ()
{    
  CGRect keyboardFrame;
	UITextField *activeTextField;
}
@end

@implementation LFBoxScroll

- (id)initWithFrame:(CGRect)frame
{
	self = [super initWithFrame:frame];
	if (self) {        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
	}
	return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
	//Se l'utente effettua un touch sulla view nascondo la tastiera
  [super touchesBegan:touches withEvent:event];
  [self endEditing:NO];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
	//Memorizzo il TextField su cui ho il focus
	activeTextField = textField;
  [self scrollAfterTextFieldFocus];
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
	//Annullo la variabile in quanto non sto più modificando il TextField memorizzato
	activeTextField = nil;
}

-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
	//Se l'utente preme "Next" sulla tastiera, metto il focus al prossimo TextField
	if (textField.returnKeyType == UIReturnKeyNext)
	{
		[[self viewWithTag:textField.tag+1] becomeFirstResponder];
		[self scrollAfterTextFieldFocus];
	}
	return YES;
}

//Quando visualizzo la tastiera, faccio il resize della ScrollView in modo da poter scrollare solo la parte di schermo in cui la tastiera non è presente
-(void)keyboardDidShow:(NSNotification*)notification
{
    if (activeTextField != nil)
    {
        keyboardFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
	
        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardFrame.size.height, 0.0);
        self.contentInset = contentInsets;
        self.scrollIndicatorInsets = contentInsets;
	
        [self scrollAfterTextFieldFocus];
    }
}

//Quando nascondo la tastiera, faccio il resize della ScrollView in modo da scrollare a pieno schermo
-(void)keyboardWillHide:(NSNotification*)notification
{
    if (activeTextField != nil)
    {
        [UIView animateWithDuration:0.25 animations:^{
            UIEdgeInsets contentInsets = UIEdgeInsetsZero;
            self.contentInset = contentInsets;
            self.scrollIndicatorInsets = contentInsets;
        }];
    }
}

//Funzione che scrolla la vista in modo da visualizzare il TextField in cui ho il focus
-(void)scrollAfterTextFieldFocus
{
	CGPoint pt;
	CGRect rc = [activeTextField bounds];
	rc = [activeTextField convertRect:rc toView:self];
	pt = rc.origin;
	
	CGRect rect = self.frame;
	rect.size.height -= keyboardFrame.size.height;
	if (!CGRectContainsPoint(rect, activeTextField.frame.origin))
	{
		rc.size.height += 15;
		[self scrollRectToVisible:rc animated:YES];
	}
	else
	{
		pt.x = 0;
		pt.y -= 80;
		[self setContentOffset:pt animated:YES];
	}
}

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *