126 votes

Comment faire défiler l'UIScrollView lorsque le clavier apparaît ?

J'ai des problèmes avec mon code. J'essaie de déplacer le UIScrollView lorsque j'édite un UITextField qui devrait être caché par le pop du clavier.

Je suis en train de déplacer le cadre principal parce que je ne sais pas comment faire défiler les pages vers le haut dans le code. Donc, j'ai fait un peu de code, ça marche bien mais quand je modifie un champ UItext et que je passe à un autre champ UItext UITextField sans appuyer sur le bouton 'retour' la vue principale monte beaucoup trop haut.

J'ai fait un NSLog() avec mes variables size, distance et textFieldRect.origin.y comme vous pouvez le voir ci-dessous. Lorsque je mets deux UITextField au même endroit (origine y) et que je fais ce 'switch' particulier (sans appuyer sur retour), j'obtiens les mêmes chiffres, alors que mon code fonctionnait bien pour le premier UITextField mais pas pour la deuxième édition.

Regarde ça :

- (void)textFieldDidBeginEditing:(UITextField *)textField {
{
    int size;
    CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
    size = textFieldRect.origin.y + textFieldRect.size.height;
    if (change == FALSE)
    {
        size = size - distance;
    }
    if (size < PORTRAIT_KEYBOARD_HEIGHT)
    {
        distance = 0;
    }
    else if (size > PORTRAIT_KEYBOARD_HEIGHT)
    {
        distance = size - PORTRAIT_KEYBOARD_HEIGHT + 5; // +5 px for more visibility
    }
    NSLog(@"origin %f", textFieldRect.origin.y);
    NSLog(@"size %d", size);
    NSLog(@"distance %d", distance);
    CGRect viewFrame = self.view.frame;
    viewFrame.origin.y -= distance;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
    change = FALSE;
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    change = TRUE;
    CGRect viewFrame = self.view.frame;
    viewFrame.origin.y += distance;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
}

Des idées ?

1voto

Naveen Kumar M Points 4060

Essayez ce code en Swift 3 :

override func viewDidAppear(_ animated: Bool) {
    setupViewResizerOnKeyboardShown()
}

func setupViewResizerOnKeyboardShown() {
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(self.keyboardWillShowForResizing),
                                           name: Notification.Name.UIKeyboardWillShow,
                                           object: nil)
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(self.keyboardWillHideForResizing),
                                           name: Notification.Name.UIKeyboardWillHide,
                                           object: nil)
}

func keyboardWillShowForResizing(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
        let window = self.view.window?.frame {
        // We're not just minusing the kb height from the view height because
        // the view could already have been resized for the keyboard before
        self.view.frame = CGRect(x: self.view.frame.origin.x,
                                 y: self.view.frame.origin.y,
                                 width: self.view.frame.width,
                                 height: window.origin.y + window.height - keyboardSize.height)

    } else {
        debugPrint("We're showing the keyboard and either the keyboard size or window is nil: panic widely.")
    }
}

func keyboardWillHideForResizing(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        let viewHeight = self.view.frame.height
        self.view.frame = CGRect(x: self.view.frame.origin.x,
                                 y: self.view.frame.origin.y,
                                 width: self.view.frame.width,
                                 height: viewHeight) //viewHeight + keyboardSize.height

    } else {
        debugPrint("We're about to hide the keyboard and the keyboard size is nil. Now is the rapture.")
    }
}

deinit {
        NotificationCenter.default.removeObserver(self)
    }

1voto

Mikolaj Points 366

Swift 5 solution basée sur Solution Masa ci-dessus - des changements par rapport à celui-ci :

  • en utilisant keyboardFrameEndUserInfoKey au lieu de keyboardFrameBeginUserInfoKey parce que keyboardFrameBeginUserInfoKey peut, à la première présentation, renvoyer une autre valeur comme décrit par exemple ici : la hauteur du clavier varie lors de l'apparition
  • l'utilisation de "will" au lieu de "did" les notifications plus le changement des noms de clés Swift 5 : UIResponder.keyboardWillShowNotification / UIResponder.keyboardWillHideNotification au lieu de NSNotification.Name.UIKeyboardDidShow / NSNotification.Name.UIKeyboardDidHide

Code :

override func viewDidLoad() {
    super.viewDidLoad()
    registerForKeyboardNotifications()
}

func registerForKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardAppear(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDisappear(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}

@objc func onKeyboardAppear(_ notification: NSNotification) {
    guard let info = notification.userInfo, let kbSize = (info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size else { return }

    let insets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height, right: 0)

    scrollView.contentInset = insets
    scrollView.scrollIndicatorInsets = insets

    //Other changes if needed
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

0voto

Arkku Points 15523

Vous pouvez faire défiler en utilisant la propriété contentOffset en UIScrollView par exemple,

CGPoint offset = scrollview.contentOffset;
offset.y -= KEYBOARD_HEIGHT + 5;
scrollview.contentOffset = offset;

Il existe également une méthode permettant de réaliser un défilement animé.

Pour ce qui est de la raison pour laquelle votre deuxième édition ne défile pas correctement, cela pourrait être dû au fait que vous semblez supposer qu'un nouveau clavier apparaîtra chaque fois que l'édition commencera. Vous pourriez essayer de vérifier si vous avez déjà ajusté la position visible du "clavier" (et de même vérifier la visibilité du clavier à ce moment-là avant de faire marche arrière).

Une meilleure solution pourrait être d'écouter la notification du clavier, par exemple :

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

0voto

Timur Mustafaev Points 1675

En fait, vous n'avez pas besoin d'un UIScrollView pour faire cela. J'ai utilisé ce code et cela fonctionne pour moi :

-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{

   if (textField==_myTextField)
   {
      [self keyBoardAppeared];
   }
   return true;
}

-(void)textFieldDidEndEditing:(UITextField *)textField {
   if (textField==_myTextField)
   {
      [self keyBoardDisappeared];
   }
}

-(void) keyBoardAppeared
{
   CGRect frame = self.view.frame;

[UIView animateWithDuration:0.3
                      delay:0
                    options: UIViewAnimationCurveEaseOut
                 animations:^{
                     self.view.frame = CGRectMake(frame.origin.x, frame.origin.y-215, frame.size.width, frame.size.height);
                 }
                 completion:^(BOOL finished){

                 }];
}

-(void) keyBoardDisappeared
{
   CGRect frame = self.view.frame;

  [UIView animateWithDuration:0.3
                      delay:0
                    options: UIViewAnimationCurveEaseOut
                 animations:^{
                     self.view.frame = CGRectMake(frame.origin.x, frame.origin.y+215, frame.size.width, frame.size.height);
                 }
                 completion:^(BOOL finished){

                 }];
}

0voto

sdernley Points 1

Je sais que c'est une vieille question, mais j'ai pensé que cela pourrait aider d'autres personnes. Je voulais quelque chose d'un peu plus facile à mettre en œuvre pour quelques applications que j'avais, alors j'ai créé une classe pour cela. Vous pouvez la télécharger ici si vous le souhaitez : https://github.com/sdernley/iOSTextFieldHandler

Il suffit de définir tous les UITextFields pour qu'ils aient un délégué de self.

textfieldname.delegate = self;

Et ensuite, ajoutez ceci à votre contrôleur de vue avec le nom de votre scrollView et de votre bouton d'envoi.

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    [iOSTextFieldHandler TextboxKeyboardMover:containingScrollView tf:textField btn:btnSubmit];
}

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