54 votes

UITextField: déplacer la vue lorsque le clavier apparaît

Je suis actuellement en train de travailler sur une application iPhone avec un seul point de vue, qui a de multiples UITextFields pour l'entrée. Lorsque le clavier montre, il se superpose à la partie inférieure textfields. J'ai donc ajouté le textFieldDidBeginEditing: méthode, pour déplacer la vue vers le haut, qui fonctionne très bien:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    if ( ( textField != inputAmount ) && ( textField != inputAge ) ) {
    	NSTimeInterval animationDuration = 0.300000011920929;
    	CGRect frame = self.view.frame;
    	frame.origin.y -= kOFFSET_FOR_KEYBOARD;
    	frame.size.height += kOFFSET_FOR_KEYBOARD;
    	[UIView beginAnimations:@"ResizeForKeyboard" context:nil];
    	[UIView setAnimationDuration:animationDuration];
    	self.view.frame = frame;
    	[UIView commitAnimations];		
    }
}

Cette méthode vérifie si la source du message est l'un des objets textfield qui sont visibles lorsque le clavier montre, et si non, il se déplace le point de vue.

J'ai aussi ajouté l' textFieldDidEndEnditing: méthode, qui permet de déplacer la vue vers le bas à nouveau (et mise à jour de certains objets de modèle en fonction de l'évolution de l'entrée):

- (void)textFieldDidEndEditing:(UITextField *)textField {
    if ( ( textField != inputMenge ) && ( textField != inputAlter ) ) {
    	NSTimeInterval animationDuration = 0.300000011920929;
    	CGRect frame = self.view.frame;
    	frame.origin.y += kOFFSET_FOR_KEYBOARD;
    	frame.size.height -= kOFFSET_FOR_KEYBOARD;
    	[UIView beginAnimations:@"ResizeForKeyboard" context:nil];
    	[UIView setAnimationDuration:animationDuration];
    	self.view.frame = frame;
    	[UIView commitAnimations];		
    }
    // Additional Code
}

Cependant, cette solution présente des défauts simple: Quand j'ai fini d'éditer l'un des "caché" textfields et touchez un autre champ de texte, le clavier disparaît, la vue se déplace vers le bas, la vue se déplace de nouveau et le clavier s'affiche à nouveau.

Est-il possible de garder le clavier de disparaître et de réapparaître entre deux vérifications (de la "caché" textfields - pour que la vue ne se déplace que lorsque le textfield les changements d'un qui serait masquée par le clavier pour un qui n'aurait pas caché)?

47voto

Vladimir Grigorov Points 3306

Cette solution est basée sur ComSubVie.

Avantages:

  • Il prend en charge l'appareil de rotation fonctionne pour toutes les orientations;
  • Il n'a pas coder en dur les valeurs pour l'animation de la durée et de la courbe, il lit à partir du clavier de notification;
  • Il utilise UIKeyboardWillShowNotification au lieu de UIKeyboardDidShowNotification de synchroniser le clavier de l'animation et des actions personnalisées;
  • Il n'utilise pas le obsolète UIKeyboardBoundsUserInfoKey;
  • Il gère le clavier redimensionner en raison appuyant sur la clé Internationale;
  • Fuite de mémoire corrigés par l'annulation de l'inscription pour les événements de clavier;
  • Tous les clavier le code de traitement est encapsulé dans une classe séparée - KBKeyboardHandler;
  • Flexibilité - KBKeyboardHandler classe peut être facilement étendu / modifié afin de mieux répondre à des besoins spécifiques;

Limitations:

  • Fonctionne pour iOS 4 et au-dessus, il a besoin de quelques modifications pour prendre en charge les anciennes versions;
  • Il fonctionne pour les applications avec un seul UIWindow. Si vous utilisez plusieurs UIWindows, vous devrez peut-être modifier retrieveFrameFromNotification: méthode.

Utilisation:

Inclure KBKeyboardHandler.h, KBKeyboardHandler.m et KBKeyboardHandlerDelegate.h dans votre projet. Mettre en œuvre l' KBKeyboardHandlerDelegate protocole dans votre vue-contrôleur - il se compose d'une méthode unique, qui sera appelée lorsque le clavier est affiché, masqué ou sa taille est modifiée. Instancier l' KBKeyboardHandler et l'ensemble de son délégué (généralement de soi). Voir l'exemple d' MyViewController ci-dessous.

KBKeyboardHandler.h:

@protocol KBKeyboardHandlerDelegate;

@interface KBKeyboardHandler : NSObject

- (id)init;

// Put 'weak' instead of 'assign' if you use ARC
@property(nonatomic, assign) id<KBKeyboardHandlerDelegate> delegate; 
@property(nonatomic) CGRect frame;

@end

KBKeyboardHandler.m:

#import "KBKeyboardHandler.h"
#import "KBKeyboardHandlerDelegate.h"

@implementation KBKeyboardHandler

- (id)init
{
    self = [super init];
    if (self)
    {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillShow:)
                                                     name:UIKeyboardWillShowNotification
                                                   object:nil];

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillHide:)
                                                     name:UIKeyboardWillHideNotification
                                                   object:nil];
    }

    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

@synthesize delegate;
@synthesize frame;

- (void)keyboardWillShow:(NSNotification *)notification
{
    CGRect oldFrame = self.frame;    
    [self retrieveFrameFromNotification:notification];

    if (oldFrame.size.height != self.frame.size.height)
    {
        CGSize delta = CGSizeMake(self.frame.size.width - oldFrame.size.width,
                                  self.frame.size.height - oldFrame.size.height);
        if (self.delegate)
            [self notifySizeChanged:delta notification:notification];
    }
}

- (void)keyboardWillHide:(NSNotification *)notification
{
    if (self.frame.size.height > 0.0)
    {
        [self retrieveFrameFromNotification:notification];
        CGSize delta = CGSizeMake(-self.frame.size.width, -self.frame.size.height);

        if (self.delegate)
            [self notifySizeChanged:delta notification:notification];
    }

    self.frame = CGRectZero;
}

- (void)retrieveFrameFromNotification:(NSNotification *)notification
{
    CGRect keyboardRect;
    [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardRect];
    self.frame = [[UIApplication sharedApplication].keyWindow.rootViewController.view convertRect:keyboardRect fromView:nil];
}

- (void)notifySizeChanged:(CGSize)delta notification:(NSNotification *)notification
{
    NSDictionary *info = [notification userInfo];

    UIViewAnimationCurve curve;
    [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];

    NSTimeInterval duration;
    [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration];

    void (^action)(void) = ^{
        [self.delegate keyboardSizeChanged:delta];
    };

    [UIView animateWithDuration:duration
                          delay:0.0
                        options:curve
                     animations:action
                     completion:nil];    
}

@end

KBKeyboardHandlerDelegate.h:

@protocol KBKeyboardHandlerDelegate

- (void)keyboardSizeChanged:(CGSize)delta;

@end

Exemple De MyViewController.h:

@interface MyViewController : UIViewController<KBKeyboardHandlerDelegate>
...
@end

Exemple De MyViewController.m:

@implementation MyViewController
{
    KBKeyboardHandler *keyboard;
}

- (void)dealloc
{
    keyboard.delegate = nil;
    [keyboard release];
    [super dealloc];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    keyboard = [[KBKeyboardHandler alloc] init];
    keyboard.delegate = self;
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    keyboard.delegate = nil;
    [keyboard release];
    keyboard = nil;
}

- (void)keyboardSizeChanged:(CGSize)delta
{
    // Resize / reposition your views here. All actions performed here 
    // will appear animated.
    // delta is the difference between the previous size of the keyboard 
    // and the new one.
    // For instance when the keyboard is shown, 
    // delta may has width=768, height=264,
    // when the keyboard is hidden: width=-768, height=-264.
    // Use keyboard.frame.size to get the real keyboard size.

    // Sample:
    CGRect frame = self.view.frame;
    frame.size.height -= delta.height;
    self.view.frame = frame;
}

29voto

ComSubVie Points 1181

Je viens de résoudre ce problème. La solution est une combinaison d'un UIKeyboardDidShowNotification et UIKeyboardDidHideNotification observateur auprès de la ci-dessus textFieldDidBeginEditing: et textFieldDidEndEditing: méthodes.

Vous avez besoin de trois variables supplémentaires, l'un pour stocker le courant sélectionné UITextField (que j'ai nommé activeField), un pour indiquer si le point de vue actuel a été déplacé, et à indiquer si le clavier est affiché.

C'est la façon dont les deux UITextField délégué méthodes regardez maintenant:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    activeField = textField;
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    activeField = nil;
    // Additional Code
}

Lorsque la vue est chargé, les deux observateurs sont créés:

- (void)viewDidLoad {
    // Additional Code
    [[NSNotificationCenter defaultCenter] addObserver:self
    										 selector:@selector(keyboardWasShown:)
    											 name:UIKeyboardDidShowNotification
    										   object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
    										 selector:@selector(keyboardWasHidden:)
    											 name:UIKeyboardDidHideNotification
    										   object:nil];
}

Et les méthodes correspondantes sont mises en œuvre comme suit:

- (void)keyboardWasShown:(NSNotification *)aNotification {
    if ( keyboardShown )
    	return;

    if ( ( activeField != inputAmount ) && ( activeField != inputAge ) ) {
    	NSDictionary *info = [aNotification userInfo];
    	NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
    	CGSize keyboardSize = [aValue CGRectValue].size;

    	NSTimeInterval animationDuration = 0.300000011920929;
    	CGRect frame = self.view.frame;
    	frame.origin.y -= keyboardSize.height-44;
    	frame.size.height += keyboardSize.height-44;
    	[UIView beginAnimations:@"ResizeForKeyboard" context:nil];
    	[UIView setAnimationDuration:animationDuration];
    	self.view.frame = frame;
    	[UIView commitAnimations];

    	viewMoved = YES;
    }

    keyboardShown = YES;
}

- (void)keyboardWasHidden:(NSNotification *)aNotification {
    if ( viewMoved ) {
    	NSDictionary *info = [aNotification userInfo];
    	NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
    	CGSize keyboardSize = [aValue CGRectValue].size;

    	NSTimeInterval animationDuration = 0.300000011920929;
    	CGRect frame = self.view.frame;
    	frame.origin.y += keyboardSize.height-44;
    	frame.size.height -= keyboardSize.height-44;
    	[UIView beginAnimations:@"ResizeForKeyboard" context:nil];
    	[UIView setAnimationDuration:animationDuration];
    	self.view.frame = frame;
    	[UIView commitAnimations];

    	viewMoved = NO;
    }

    keyboardShown = NO;
}

Ce code fonctionne maintenant comme prévu. Le clavier n'est rejetée lorsque le bouton est pressé, sinon il reste visible et la vue ne sont pas déplacés.

Comme une note complémentaire, je pense qu'il est possible d'obtenir l' animationDuration dynamiquement en demandant à l' NSNotification objet, puisque j'ai déjà joué avec une solution similaire, mais ne pas le faire fonctionner (c'est le cas maintenant).

2voto

coolcool1994 Points 526

Ce contrôleur de vue doit être UITextView Delegate et vous devez définir self.textview.delegate = self dans viewdidload

  -(void) textViewDidBeginEditing:(UITextView *)textView
    {
        NSLog(@"%f",self.view.frame.origin.y);
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.25f];
        CGRect frame = self.view.frame;
        frame.origin.y =frame.origin.y -204;
        [self.view setFrame:frame];
        [UIView commitAnimations];
    }

-(void) textViewDidEndEditing:(UITextView *)textView
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.25f];
    CGRect frame = self.view.frame;
    frame.origin.y = frame.origin.y + 204;
    [self.view setFrame:frame];
    [UIView commitAnimations];
}
 

0voto

utkal patel Points 251

J'ai votre problème, faites une chose simple, donnez simplement un point de vente à UIScrollview. Définissez la propriété Tag unique pour chaque champ de texte affiché.

 -(void)textFieldDidBeginEditing:(UITextField *)textField
    {   
        switch (textField.tag)
        {
            case 2:    //can be your textfiled tag
              { CGPoint scrollPoint = CGPointMake(0, yourtextfield.frame.origin.y-150); 
                                           //set figure y-150 as per your comfirt
                  [scrollview setContentOffset:scrollPoint animated:YES]; 
             }break;

              case 3:   
              { CGPoint scrollPoint = CGPointMake(0, yourtextfield.frame.origin.y-180); 
                                           //set figure y-180 as per your comfirt
                  [scrollview setContentOffset:scrollPoint animated:YES]; 
             }break;

             ...

         }
    }

    -(void)textFieldDidEndEditing:(UITextField *)textField{

        if(textField.tag==3){
            [scrollview setContentOffset:CGPointZero animated:YES];
                }
         //set the last textfield when you want to disappear keyboard.
    }
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X