web-dev-qa-db-fra.com

Faire défiler un UITableView lorsque le champ de texte est sélectionné

Après beaucoup d'essais et d'erreurs, j'abandonne et pose la question. J'ai vu beaucoup de gens avec des problèmes similaires mais je ne peux pas obtenir toutes les réponses pour bien travailler.

J'ai un UITableView qui est composé de cellules personnalisées. Les cellules sont constituées de 5 champs de texte juxtaposés (un peu comme une grille).

Lorsque j'essaie de faire défiler et d'éditer les cellules au bas de la UITableView, je ne parviens pas à positionner correctement mes cellules au-dessus du clavier.

J'ai vu de nombreuses réponses parler de changements de tailles de vues, etc., mais aucune d'entre elles n'a bien fonctionné jusqu'à présent.

Quelqu'un pourrait-il préciser la "bonne" façon de procéder avec un exemple de code concret?

236
Jonathan

Si vous utilisez UITableViewController au lieu de UIViewController, il le fera automatiquement.

121
Sam Ho

La fonction qui fait le défilement pourrait être beaucoup plus simple:

- (void) textFieldDidBeginEditing:(UITextField *)textField {
    UITableViewCell *cell;

    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
    // Load resources for iOS 6.1 or earlier
        cell = (UITableViewCell *) textField.superview.superview;

    } else {
        // Load resources for iOS 7 or later
        cell = (UITableViewCell *) textField.superview.superview.superview; 
       // TextField -> UITableVieCellContentView -> (in iOS 7!)ScrollView -> Cell!
    }
    [tView scrollToRowAtIndexPath:[tView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

C'est tout. Aucun calcul du tout.

91
user91083

Je fais quelque chose de très similaire, c'est générique, pas besoin de calculer quelque chose de spécifique pour votre code ..__, vérifiez les remarques sur le code:

Dans MyUIViewController.h

@interface MyUIViewController: UIViewController <UITableViewDelegate, UITableViewDataSource>
{
     UITableView *myTableView;
     UITextField *actifText;
}

@property (nonatomic, retain) IBOutlet UITableView *myTableView;
@property (nonatomic, retain) IBOutlet UITextField *actifText;

- (IBAction)textFieldDidBeginEditing:(UITextField *)textField;
- (IBAction)textFieldDidEndEditing:(UITextField *)textField;

-(void) keyboardWillHide:(NSNotification *)note;
-(void) keyboardWillShow:(NSNotification *)note;

@end

Dans MyUIViewController.m

@implementation MyUIViewController

@synthesize myTableView;
@synthesize actifText;

- (void)viewDidLoad 
{
    // Register notification when the keyboard will be show
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillShow:)
                                          name:UIKeyboardWillShowNotification
                                          object:nil];

    // Register notification when the keyboard will be hide
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillHide:)
                                          name:UIKeyboardWillHideNotification
                                          object:nil];
}

// To be link with your TextField event "Editing Did Begin"
//  memoryze the current TextField
- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
    self.actifText = textField;
}

// To be link with your TextField event "Editing Did End"
//  release current TextField
- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
    self.actifText = nil;
}

-(void) keyboardWillShow:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    // Start animation
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Reduce size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height -= keyboardBounds.size.height;
    else 
        frame.size.height -= keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    // Scroll the table view to see the TextField just above the keyboard
    if (self.actifText)
      {
        CGRect textFieldRect = [self.myTableView convertRect:self.actifText.bounds fromView:self.actifText];
        [self.myTableView scrollRectToVisible:textFieldRect animated:NO];
      }

    [UIView commitAnimations];
}

-(void) keyboardWillHide:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Increase size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height += keyboardBounds.size.height;
    else 
        frame.size.height += keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    [UIView commitAnimations];
}

@end

Version Swift 1.2+:

class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var activeText: UITextField!
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillShow:"),
            name: UIKeyboardWillShowNotification,
            object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillHide:"),
            name: UIKeyboardWillHideNotification,
            object: nil)
    }

    func textFieldDidBeginEditing(textField: UITextField) {
        activeText = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        activeText = nil
    }

    func keyboardWillShow(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height -= keyboardSize.height
            tableView.frame = frame
            if activeText != nil {
                let rect = tableView.convertRect(activeText.bounds, fromView: activeText)
                tableView.scrollRectToVisible(rect, animated: false)
            }
            UIView.commitAnimations()
        }
    }

    func keyboardWillHide(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height += keyboardSize.height
            tableView.frame = frame
            UIView.commitAnimations()
        }
    }
}
68
ZeLegolas

J'ai eu le même problème, mais j'ai remarqué qu'il n'apparaissait que dans une vue. Alors j'ai commencé à chercher les différences entre les contrôleurs.

J'ai découvert que le comportement de défilement est défini dans - (void)viewWillAppear:(BOOL)animated de la super instance.

Veillez donc à implémenter comme ceci:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // your code
}

Et peu importe si vous utilisez UIViewController ou UITableViewController; vérifié en mettant une UITableView comme une sous-vue de self.view dans la UIViewController. C'était le même comportement. La vue ne permettait pas de faire défiler si l'appel [super viewWillAppear:animated]; était manquant.

44
ph.dev

La solution la plus simple pour Swift 3, basée sur la solution Bartłomiej Semańczyk :

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

// MARK: Keyboard Notifications

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
        tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.2, animations: {
        // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
        self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
    })
}
40
squall2022

j'ai peut-être manqué cela, car je n'ai pas lu le post en entier, mais ce que j'ai proposé semble d'une simplicité trompeuse. Je n'ai pas mis cela à rude épreuve, à tester dans toutes les situations, mais il semble que cela devrait fonctionner très bien.

ajustez simplement le contentInset de la table par la hauteur du clavier, puis faites défiler la cellule vers le bas:

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

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    self.myTableView.contentInset = contentInsets;
    self.myTableView.scrollIndicatorInsets = contentInsets;

    [self.myTableView scrollToRowAtIndexPath:self.currentField.indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}

et bien sur

- (void)keyboardWasHidden:(NSNotification *)aNotification
{
    [UIView animateWithDuration:.3 animations:^(void) 
    {
        self.myTableView.contentInset = UIEdgeInsetsZero;
        self.myTableView.scrollIndicatorInsets = UIEdgeInsetsZero;
    }];
}

est-ce trop simple? est-ce que je manque quelque chose? jusqu'à présent, cela fonctionne bien pour moi, mais comme je l'ai dit, je ne l'ai pas fait passer à travers l'essoreuse ...

37
mickm

Je pense avoir trouvé la solution qui correspond au comportement des applications Apple.

Tout d’abord, dans votre viewWillAppear: abonnez-vous aux notifications du clavier pour que vous sachiez quand le clavier sera affiché et masqué, et le système vous indiquera la taille du clavier, mais n’oubliez pas de vous désinscrire de votre viewWillDisappear :.

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

Implémentez des méthodes similaires à celles décrites ci-dessous pour ajuster la taille de votre tableView en fonction de la zone visible une fois que le clavier est affiché. Ici, je surveille l’état du clavier séparément afin de pouvoir choisir moi-même quand redéfinir la tableView à pleine hauteur, puisque vous recevez ces notifications à chaque changement de champ. N'oubliez pas d'implémenter keyboardWillHide: et choisissez un emplacement approprié pour corriger la taille de votre table.

-(void) keyboardWillShow:(NSNotification *)note
{
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &keyboardBounds];
    keyboardHeight = keyboardBounds.size.height;
    if (keyboardIsShowing == NO)
    {
        keyboardIsShowing = YES;
        CGRect frame = self.view.frame;
        frame.size.height -= keyboardHeight;

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationBeginsFromCurrentState:YES];
        [UIView setAnimationDuration:0.3f];
        self.view.frame = frame;
        [UIView commitAnimations];
    }
}

Maintenant, voici le bit de défilement, nous travaillons d’abord sur quelques tailles, puis nous voyons où nous nous situons dans la zone visible et nous définissons le rect auquel nous voulons faire défiler la moitié de la vue au-dessus ou au-dessous du milieu du champ de texte. sur où il est dans la vue. Dans ce cas, nous avons un tableau de UITextFields et une énumération qui les garde, donc multiplier le paramètre rowHeight par le numéro de la ligne nous donne le décalage réel du cadre dans cette vue externe.

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGRect frame = textField.frame;
    CGFloat rowHeight = self.tableView.rowHeight;
    if (textField == textFields[CELL_FIELD_ONE])
    {
        frame.Origin.y += rowHeight * CELL_FIELD_ONE;
    }
    else if (textField == textFields[CELL_FIELD_TWO])
    {
        frame.Origin.y += rowHeight * CELL_FIELD_TWO;
    }
    else if (textField == textFields[CELL_FIELD_THREE])
    {
        frame.Origin.y += rowHeight * CELL_FIELD_THREE;
    }
    else if (textField == textFields[CELL_FIELD_FOUR])
    {
        frame.Origin.y += rowHeight * CELL_FIELD_FOUR;
    }
    CGFloat viewHeight = self.tableView.frame.size.height;
    CGFloat halfHeight = viewHeight / 2;
    CGFloat midpoint = frame.Origin.y + (textField.frame.size.height / 2);
    if (midpoint < halfHeight)
    {
        frame.Origin.y = 0;
        frame.size.height = midpoint;
    }
    else
    {
        frame.Origin.y = midpoint;
        frame.size.height = midpoint;
    }
    [self.tableView scrollRectToVisible:frame animated:YES];
}

Cela semble fonctionner assez bien.

35
Michael Baltaks

Si vous pouvez utiliser UITableViewController, vous obtenez la fonctionnalité gratuitement. Parfois, cependant, ce n'est pas une option, en particulier si vous avez besoin de plusieurs vues, pas seulement de la UITableView.

Certaines des solutions présentées ici ne fonctionnent pas sur iOS ≥4, certaines ne fonctionnent pas sur iPad ou en mode paysage, d'autres ne fonctionnent pas sur les claviers Bluetooth (pour lesquels nous ne voulons pas de défilement), d'autres pas fonctionne lors de la commutation entre plusieurs champs de texte. Donc, si vous choisissez une solution, assurez-vous de tester ces cas. C’est la solution que nous utilisation used dans InAppSettingsKit :

- (void)_keyboardWillShow:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        // we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
        NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
        if (!keyboardFrameValue) {
            keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
        }

        // Reduce the tableView height by the part of the keyboard that actually covers the tableView
        CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            windowRect = IASKCGRectSwap(windowRect);
        }
        CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
        }
        CGRect frame = _tableView.frame;
        frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = frame;
        [UIView commitAnimations];

        UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
        NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

        // iOS 3 sends hide and show notifications right after each other
        // when switching between textFields, so cancel -scrollToOldPosition requests
        [NSObject cancelPreviousPerformRequestsWithTarget:self];

        [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
    }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)_keyboardWillHide:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = self.view.bounds;
        [UIView commitAnimations];

        [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
    }
}   

Voici le code complet de la classe dans InAppSettingsKit. Pour le tester, utilisez le volet enfant "Liste complète" dans lequel vous pouvez tester les scénarios mentionnés ci-dessus.

35
Ortwin Gentz

La solution la plus simple pour Swift :

override func viewDidLoad() {
    super.viewDidLoad()

    searchBar?.becomeFirstResponder()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillHide(_:)), name: UIKeyboardDidHideNotification, object: nil)
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue.size.height {
            tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    UIView.animateWithDuration(0.2, animations: { self.table_create_issue.contentInset = UIEdgeInsetsMake(0, 0, 0, 0) })
    // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
    }
23

J'espère que vous avez déjà une solution en lisant tous ceux-là. Mais j'ai trouvé ma solution comme suit. Je m'attends à ce que vous ayez déjà une cellule avec UITextField. Donc, en cours de préparation, conservez simplement l'index de la ligne dans la balise du champ de texte.

cell.textField.tag = IndexPath.row;

Créez une instance activeTextField de UITextField avec une étendue globale comme ci-dessous: 

@interface EditViewController (){

    UITextField *activeTextField;

}

Donc, maintenant, il suffit de copier coller mon code à la fin. Et n'oubliez pas d'ajouter UITextFieldDelegate

#pragma mark - TextField Delegation

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

    activeTextField = textField;

    return YES;
}

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

    activeTextField = nil;

}

Enregistre le clavier notifications

#pragma mark - Keyboard Activity

- (void)registerForKeyboardNotifications

{

    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWasShown:)

                                             name:UIKeyboardDidShowNotification object:nil];



    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWillBeHidden:)

                                             name:UIKeyboardWillHideNotification object:nil];



}

Poignées Clavier Notifications:

Appelé lorsque la UIKeyboardDidShowNotification est envoyée.

- (void)keyboardWasShown:(NSNotification*)aNotification

{

    NSDictionary* info = [aNotification userInfo];

    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);

    [self.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

    NSIndexPath *currentRowIndex = [NSIndexPath indexPathForRow:activeTextField.tag inSection:0];

    [self.tableView scrollToRowAtIndexPath:currentRowIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];

}

Appelé lorsque la UIKeyboardWillHideNotification est envoyée

- (void)keyboardWillBeHidden:(NSNotification*)aNotification

{

    UIEdgeInsets contentInsets = UIEdgeInsetsZero;

    [self.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

}

Maintenant, une chose est laissée, appelez la méthode registerForKeyboardNotifications dans à la méthode ViewDidLoad comme suit:

- (void)viewDidLoad {

    [super viewDidLoad];

    // Registering keyboard notification

    [self registerForKeyboardNotifications];

    // Your codes here...

}

Vous avez terminé, espérons que votre textFields ne sera plus masqué par le clavier.

7

En combinant et en complétant les blancs de plusieurs réponses (en particulier Ortwin Gentz, utilisateur 98013) et un autre message, cela fonctionnera immédiatement pour le SDK 4.3 sur un iPad en mode Portrait ou Paysage: 

@implementation UIView (FindFirstResponder)
- (UIResponder *)findFirstResponder
{
  if (self.isFirstResponder) {        
    return self;     
  }

  for (UIView *subView in self.subviews) {
    UIResponder *firstResponder = [subView findFirstResponder];
    if (firstResponder != nil) {
      return firstResponder;
    }
  }

  return nil;
}
@end

@implementation MyViewController

- (UIResponder *)currentFirstResponder {
  return [self.view findFirstResponder];
}

- (IBAction)editingEnded:sender {
  [sender resignFirstResponder];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
  [textField resignFirstResponder];
  return NO;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField {
  UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
  [_tableView scrollToRowAtIndexPath:[_tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillShow:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {
    NSDictionary* userInfo = [notification userInfo];

    // we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
    NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
    if (!keyboardFrameValue) {
      keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
    }

    // Reduce the tableView height by the part of the keyboard that actually covers the tableView
    CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
    CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
    CGRect frame = _tableView.frame;
    if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
      windowRect = CGRectMake(windowRect.Origin.y, windowRect.Origin.x, windowRect.size.height, windowRect.size.width);
      viewRectAbsolute = CGRectMake(viewRectAbsolute.Origin.y, viewRectAbsolute.Origin.x, viewRectAbsolute.size.height, viewRectAbsolute.size.width);
    }
    frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = frame;
    [UIView commitAnimations];

    UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
    NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

    // iOS 3 sends hide and show notifications right after each other
    // when switching between textFields, so cancel -scrollToOldPosition requests
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    _topmostRowBeforeKeyboardWasShown = [[_tableView indexPathsForVisibleRows] objectAtIndex:0];
    [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
  }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillHide:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {

    NSDictionary* userInfo = [notification userInfo];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = self.view.bounds;
    [UIView commitAnimations];

    [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
  }
}   

@end
6
Colin

Mon approche:

Je commence par sous-classer UITextField et j'ajoute une propriété indexPath. Dans la méthode cellFor ... Méthode, je remets la propriété indexPath.

Puis j'ajoute le code suivant:

UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:textField.indexPath];

CGPoint cellPoint = [cell convertPoint:textField.center toView:self.tableView];
[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, cellPoint.y-50);}];

à la textFieldShould/WillBegin ... etc.

Lorsque le clavier disparaît, vous devez l'inverser avec:

[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, 0);}];
5
Sven

Si vous utilisez Three20, utilisez la propriété autoresizesForKeyboard. Il suffit de définir dans la méthode -initWithNibName:bundle de votre contrôleur de vue

self.autoresizesForKeyboard = YES

Cela prend soin de:

  1. Écouter les notifications au clavier et ajuster le cadre de la vue tableau
  2. Défilement jusqu'au premier intervenant

Fait et fait.

5
Think Top Down

LA BONNE RÉPONSE est la réponse de Sam Ho:

"Si vous utilisez UITableViewController au lieu de UIViewController, il le fera automatiquement.".

Assurez-vous simplement de connecter votre UITableView à la propriété TableView de UITableViewController (par exemple, ne l'ajoutez pas en tant que sous-vue de la propriété View de UITableViewController).

Veillez également à définir la propriété AutoresizingMask de votre UITableView sur FlexibleHeight.

5
Marcel W

Si vous utilisez une uitableview pour placer vos champs de texte ( de Jeff Lamarche ), vous pouvez simplement faire défiler la vue tableau en utilisant la méthode delegate comme ceci. 

(Remarque: mes champs de texte sont stockés dans un tableau avec le même index que la ligne dans la table.)

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

        int index;
        for(UITextField *aField in textFields){

            if (textField == aField){
                index = [textFields indexOfObject:aField]-1;
            }
        }

         if(index >= 0) 
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];

        [super textFieldDidBeginEditing:textField];
    }
5
Corey Floyd

Les notifications au clavier fonctionnent, mais l'exemple de code d'Apple pour cela suppose que la vue de défilement est la vue racine de la fenêtre. Ce n'est généralement pas le cas. Vous devez compenser les barres d'onglets, etc., pour obtenir le bon décalage.

C'est plus facile qu'il n'y paraît. Voici le code que j'utilise dans un UITableViewController. Il a deux variables d'instance, hiddenRect et keyboardShown.

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification {
    if (keyboardShown)
        return;

    NSDictionary* info = [aNotification userInfo];

    // Get the frame of the keyboard.
    NSValue *centerValue = [info objectForKey:UIKeyboardCenterEndUserInfoKey];
    NSValue *boundsValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
    CGPoint keyboardCenter = [centerValue CGPointValue];
    CGRect keyboardBounds = [boundsValue CGRectValue];
    CGPoint keyboardOrigin = CGPointMake(keyboardCenter.x - keyboardBounds.size.width / 2.0,
                                         keyboardCenter.y - keyboardBounds.size.height / 2.0);
    CGRect keyboardScreenFrame = { keyboardOrigin, keyboardBounds.size };


    // Resize the scroll view.
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = scrollView.frame;
    CGRect keyboardFrame = [scrollView.superview convertRect:keyboardScreenFrame fromView:nil];
    hiddenRect = CGRectIntersection(viewFrame, keyboardFrame);

    CGRect remainder, slice;
    CGRectDivide(viewFrame, &slice, &remainder, CGRectGetHeight(hiddenRect), CGRectMaxYEdge);
    scrollView.frame = remainder;

    // Scroll the active text field into view.
    CGRect textFieldRect = [/* selected cell */ frame];
    [scrollView scrollRectToVisible:textFieldRect animated:YES];

    keyboardShown = YES;
}


// Called when the UIKeyboardDidHideNotification is sent
- (void)keyboardWasHidden:(NSNotification*)aNotification
{
    // Reset the height of the scroll view to its original value
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = [scrollView frame];
    scrollView.frame = CGRectUnion(viewFrame, hiddenRect);

    keyboardShown = NO;
}
5
Dustin Voss

Utilisez la méthode UITextField'sdelegate:

Rapide

func textFieldShouldBeginEditing(textField: UITextField) -> bool {
  let txtFieldPosition = textField.convertPoint(textField.bounds.Origin, toView: yourTableViewHere)
  let indexPath = yourTablViewHere.indexPathForRowAtPoint(txtFieldPosition)
  if indexPath != nil {
     yourTablViewHere.scrollToRowAtIndexPath(indexPath!, atScrollPosition: .Top, animated: true)
  }
  return true
}

Objectif c

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
  CGPoint txtFieldPosition = [textField convertPoint:CGPointZero toView: yourTablViewHere];
  NSLog(@"Begin txtFieldPosition : %@",NSStringFromCGPoint(txtFieldPosition));
  NSIndexPath *indexPath = [yourTablViewHere indexPathForRowAtPoint:txtFieldPosition];

  if (indexPath != nil) {
     [yourTablViewHere scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
  }
  return YES;
}
5
Paresh Navadiya

Une solution plus rationnelle. Il se glisse dans les méthodes de délégué UITextField afin qu'il ne soit pas nécessaire de modifier les notifications avec UIKeyboard.

Notes d'implémentation:

kSettingsRowHeight - la hauteur d'un UITableViewCell.

offsetTarget et offsetThreshold sont basés sur kSettingsRowHeight. Si vous utilisez une hauteur de ligne différente, définissez ces valeurs sur la propriété y du point. [alt: calcule le décalage de ligne d'une manière différente.]

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
CGFloat offsetTarget    = 113.0f; // 3rd row
CGFloat offsetThreshold = 248.0f; // 6th row (i.e. 2nd-to-last row)

CGPoint point = [self.tableView convertPoint:CGPointZero fromView:textField];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];

CGRect frame = self.tableView.frame;
if (point.y > offsetThreshold) {
    self.tableView.frame = CGRectMake(0.0f,
                      offsetTarget - point.y + kSettingsRowHeight,
                      frame.size.width,
                      frame.size.height);
} else if (point.y > offsetTarget) {
    self.tableView.frame = CGRectMake(0.0f,
                      offsetTarget - point.y,
                      frame.size.width,
                      frame.size.height);
} else {
    self.tableView.frame = CGRectMake(0.0f,
                      0.0f,
                      frame.size.width,
                      frame.size.height);
}

[UIView commitAnimations];

return YES;

}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];

CGRect frame = self.tableView.frame;
self.tableView.frame = CGRectMake(0.0f,
                  0.0f,
                  frame.size.width,
                  frame.size.height);

[UIView commitAnimations];

return YES;

}

4
Kelvin

J'ai rencontré quelque chose comme votre problème (je voulais un écran similaire aux paramètres de l'iPhone.app avec un tas de cellules modifiables empilées les unes sur les autres) et j'ai constaté que cette approche fonctionnait bien:

glisse les champs uitext pour éviter

4
drewh

Puisque vous avez des champs de texte dans une table, la meilleure façon de le redimensionner est de redimensionner la table. Vous devez définir le paramètre tableView.frame pour qu’il soit plus petit en hauteur de la taille du clavier (environ 165 pixels), puis agrandissez-le à nouveau lorsque le clavier est licencié.

Vous pouvez également éventuellement désactiver l'interaction utilisateur pour la tableView à ce moment-là, si vous ne souhaitez pas que l'utilisateur fasse défiler l'écran.

Un exemple dans Swift, utilisant le point exact du champ de texte de Obtenir indexPath de UITextField dans UITableViewCell avec Swift :

func textFieldDidBeginEditing(textField: UITextField) {
    let pointInTable = textField.convertPoint(textField.bounds.Origin, toView: self.accountsTableView)
    let textFieldIndexPath = self.accountsTableView.indexPathForRowAtPoint(pointInTable)
    accountsTableView.scrollToRowAtIndexPath(textFieldIndexPath!, atScrollPosition: .Top, animated: true)
}
2
ginchly

Fil de discussion très intéressant, j’ai également été confronté au même problème qui risque d’être plus grave parce que

  1. J'utilisais une cellule personnalisée et le champ de texte était à l'intérieur.
  2. Je devais utiliser UIViewController pour répondre à mes besoins, je ne pouvais donc pas profiter de UITableViewController.
  3. J'avais des critères de filtrage/tri dans ma cellule de table, c.-à-d. Que les cellules continuent à changer et à garder une trace du chemin d'indexation et que tout ne changera rien.

Alors lisez les discussions ici et implémentez ma version, ce qui m’a aidé à remonter le contenu de mon iPad dans landscape mode . Voici du code (ce n’est pas infaillible et tout, mais cela a résolu mon problème) Vous devez d’abord avoir un délégué dans votre classe de cellule personnalisée. Celui-ci commence par la modification, il envoie le champ de texte à votre contrôleur de vue et définit le champ active = le champ de texte ici.

// MISE EN OEUVRE POUR GÉRER LE MODE PAYSAGE UNIQUEMENT

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbValue = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect aRect = myTable.frame;

    CGSize kbSize = CGSizeMake(kbValue.height, kbValue.width);

    aRect.size.height -= kbSize.height+50;
// This will the exact rect in which your textfield is present
        CGRect rect =  [myTable convertRect:activeField.bounds fromView:activeField];
// Scroll up only if required
    if (!CGRectContainsPoint(aRect, rect.Origin) ) {


            [myTable setContentOffset:CGPointMake(0.0, rect.Origin.y) animated:YES];

    }


}

// Appelé lorsque la notification UIKeyboardWillHideNotification est envoyée

- (void)keyboardWillHide:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    myTable.contentInset = contentInsets;
    myTable.scrollIndicatorInsets = contentInsets;
    NSDictionary* info = [aNotification userInfo];
    CGSize kbValue = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGSize kbSize = CGSizeMake(kbValue.height, kbValue.width);
    CGRect bkgndRect = activeField.superview.frame;
    bkgndRect.size.height += kbSize.height;
    [activeField.superview setFrame:bkgndRect];
    [myTable setContentOffset:CGPointMake(0.0, 10.0) animated:YES];
}

-anoop4real

2
anoop4real

Je viens de résoudre un tel problème par moi-même après avoir évoqué une multitude de solutions trouvées via Google et Stack Overflow.

Tout d’abord, assurez-vous que vous avez configuré un IBOutlet de votre UIScrollView, Ensuite, examinez de plus près/ Apple Doc: Gestion du clavier . Enfin, si vous pouvez faire défiler l’arrière-plan, mais le clavier couvre toujours les champs de texte, s'il vous plaît jeter un oeil à ce morceau de code:

// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;

if (aRect.size.height < activeField.frame.Origin.y+activeField.frame.size.height) {

    CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.Origin.y+activeField.frame.size.height-aRect.size.height);

    [scrollView setContentOffset:scrollPoint animated:YES];

La principale différence entre cette pièce et celle d'Apple réside dans la condition if. Je crois que le calcul par Apple de la distance de défilement et de la condition selon laquelle les champs de texte couverts par le clavier ne sont pas exacts a été modifié comme ci-dessus.

Laissez-moi savoir si cela fonctionne

2
dumbfingers

J'ai essayé à peu près la même approche et suis parvenu à un code plus simple et plus petit pour le même . J'ai créé un iTextView IBOutlet et associé à UITextView dans l'IB.

 -(void)keyboardWillShow:(NSNotification *)notification
    {
        NSLog(@"Keyboard");
        CGRect keyFrame = [[[notification userInfo]objectForKey:UIKeyboardFrameEndUserInfoKey]CGRectValue];

        [UIView beginAnimations:@"resize view" context:nil];
        [UIView setAnimationCurve:1];
        [UIView setAnimationDuration:1.0];
        CGRect frame = iTableView.frame;
        frame.size.height = frame.size.height -  keyFrame.size.height;
        iTableView.frame = frame;
        [iTableView scrollRectToVisible:frame animated:YES];
        [UIView commitAnimations];

    }
2
thesummersign

Cela fonctionne parfaitement, et sur iPad aussi.

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

    if(textField == textfield1){
            [accountName1TextField becomeFirstResponder];
        }else if(textField == textfield2){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield3 becomeFirstResponder];

        }else if(textField == textfield3){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield4 becomeFirstResponder];

        }else if(textField == textfield4){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield5 becomeFirstResponder];

        }else if(textField == textfield5){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:3 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield6 becomeFirstResponder];

        }else if(textField == textfield6){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:4 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield7 becomeFirstResponder];

        }else if(textField == textfield7){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:5 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield8 becomeFirstResponder];

        }else if(textField == textfield8){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:6 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield9 becomeFirstResponder];

        }else if(textField == textfield9){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:7 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textField resignFirstResponder];
        }
2
WrightsCS

Swift 4.2 solution complète

J'ai créé Gist avec un ensemble de protocoles qui simplifie le travail d'ajout d'espace supplémentaire lorsque le clavier est affiché, masqué ou modifié.

Caractéristiques:

  • Fonctionne correctement avec les changements de cadre du clavier (par exemple, les changements de hauteur du clavier comme emojii → clavier normal).
  • Prise en charge de TabBar & ToolBar pour l'exemple UITableView (dans d'autres exemples, vous recevez des encarts incorrects).
  • Durée de l'animation dynamique (non codée en dur).
  • Approche axée sur le protocole qui pourrait être facilement modifiée pour vos besoins.

Usage

Exemple d'utilisation basique dans le contrôleur de vue contenant une vue de défilement (la vue de tableau est également prise en charge bien sûr).

class SomeViewController: UIViewController {
  @IBOutlet weak var scrollView: UIScrollView!

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    addKeyboardFrameChangesObserver()
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    removeKeyboardFrameChangesObserver()
  }
}

extension SomeViewController: ModifableInsetsOnKeyboardFrameChanges {
  var scrollViewToModify: UIScrollView { return scrollView }
}

Noyau: observateur des changements de cadre

Le protocole KeyboardChangeFrameObserver déclenchera un événement chaque fois que le cadre du clavier a été modifié (y compris l'affichage, le masquage, le changement de cadre).

  1. Appelez addKeyboardFrameChangesObserver() à viewWillAppear() ou une méthode similaire.
  2. Appelez removeKeyboardFrameChangesObserver() à viewWillDisappear() ou une méthode similaire.

Mise en oeuvre: vue défilante

Le protocole ModifableInsetsOnKeyboardFrameChanges ajoute le support UIScrollView au protocole principal. Il modifie les incrustations de la vue de défilement lorsque le cadre du clavier est modifié.

Votre classe doit définir la vue de défilement, les incrustations seront augmentées/diminuées lors des modifications du cadre du clavier.

var scrollViewToModify: UIScrollView { get }
2
Vasily

Cette solution fonctionne pour moi, veuillez noter la ligne

[tableView setContentOffset:CGPointMake(0.0, activeField.frame.Origin.y-kbSize.height+160) animated:YES];

Vous pouvez changer la valeur 160 pour que cela fonctionne avec vous

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = activeField.superview.frame;
                        bkgndRect.size.height += kbSize.height;
     [activeField.superview setFrame:bkgndRect];
     [tableView setContentOffset:CGPointMake(0.0, activeField.frame.Origin.y-kbSize.height+160) animated:YES];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
   activeField = textField;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
 {
     activeField = nil;
 }
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    tableView.contentInset = contentInsets;
    tableView.scrollIndicatorInsets = contentInsets;
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = activeField.superview.frame;
    //bkgndRect.size.height += kbSize.height;
    [activeField.superview setFrame:bkgndRect];
    [tableView setContentOffset:CGPointMake(0.0, activeField.frame.Origin.y-kbSize.height) animated:YES];
}
2
hiennt

Ainsi, après des heures de travail exténuant à essayer d’utiliser ces solutions actuelles (et totalement défaillantes), j’ai finalement réussi à bien faire fonctionner les choses et à les mettre à jour pour utiliser les nouveaux blocs d’animation. Ma réponse est entièrement basée sur réponse d'Ortwin ci-dessus .

Donc, pour une raison quelconque, le code ci-dessus ne fonctionnait tout simplement pas pour moi. Ma configuration semblait assez semblable à celle des autres, mais peut-être parce que j'étais sur un iPad ou une version 4.3 ... aucune idée. Il faisait des calculs loufoques et tirait ma tableview de l'écran.

Voir le résultat final de ma solution: http://screencast.com/t/hjBCuRrPC (Veuillez ignorer la photo. :-P)

Alors, je suis allé avec l'essentiel de ce que faisait Ortwin, mais j'ai changé la façon dont il faisait des calculs pour ajouter la taille Origin.y & size.height de ma vue de table à la hauteur du clavier. Lorsque je soustrais la hauteur de la fenêtre de ce résultat, cela me dit combien d'intersection il y a. Si sa valeur est supérieure à 0 (il y a un certain chevauchement), j'effectue l'animation de la hauteur de l'image. 

En outre, certains problèmes de résolution ont été résolus en 1) En attendant de faire défiler la cellule jusqu'à la fin de l'animation et 2) en utilisant l'option UIViewAnimationOptionBeginFromCurrentState lors du masquage du clavier.

Quelques choses à noter. 

  • _topmostRowBeforeKeyboardWasShown & _originalFrame sont des variables d'instance déclarées dans l'en-tête.
  • self.guestEntryTableView est mon tableView (je suis dans un fichier externe)
  • IASKCGRectSwap est la méthode utilisée par Ortwin pour inverser les coordonnées d'un cadre.
  • Je mets à jour la hauteur de la table uniquement si au moins 50 pixels de celle-ci sont visibles
  • Étant donné que je ne suis pas dans un UIViewController, je n'ai pas d'auto-visualisation, je ramène donc la tableView à son cadre d'origine

Encore une fois, je ne me serais pas approché de cette réponse si je n'avais pas fourni le cœur de la question à Ortwin. Voici le code:

- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
    self.activeTextField = textField;

    if ([self.guestEntryTableView indexPathsForVisibleRows].count) {
        _topmostRowBeforeKeyboardWasShown = (NSIndexPath*)[[self.guestEntryTableView indexPathsForVisibleRows] objectAtIndex:0];
    } else {
        // this should never happen
        _topmostRowBeforeKeyboardWasShown = [NSIndexPath indexPathForRow:0 inSection:0];
        [textField resignFirstResponder];
    }
}

- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
    self.activeTextField = nil;
}

- (void)keyboardWillShow:(NSNotification*)notification {
    NSDictionary* userInfo = [notification userInfo];

    NSValue* keyboardFrameValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];

    // Reduce the tableView height by the part of the keyboard that actually covers the tableView
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
    CGRect viewRectAbsolute = [self.guestEntryTableView convertRect:self.guestEntryTableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
    CGRect keyboardFrame = [keyboardFrameValue CGRectValue];
    if (UIInterfaceOrientationLandscapeLeft == orientation ||UIInterfaceOrientationLandscapeRight == orientation ) {
        windowRect = IASKCGRectSwap(windowRect);
        viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
        keyboardFrame = IASKCGRectSwap(keyboardFrame);
    }

    // fix the coordinates of our rect to have a top left Origin 0,0
    viewRectAbsolute = FixOriginRotation(viewRectAbsolute, orientation, windowRect.size.width, windowRect.size.height);

    CGRect frame = self.guestEntryTableView.frame;
    _originalFrame = self.guestEntryTableView.frame;

    int remainder = (viewRectAbsolute.Origin.y + viewRectAbsolute.size.height + keyboardFrame.size.height) - windowRect.size.height;

    if (remainder > 0 && !(remainder > frame.size.height + 50)) {
        frame.size.height = frame.size.height - remainder;
        float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        [UIView animateWithDuration: duration
                        animations:^{
                            self.guestEntryTableView.frame = frame;
                        }
                        completion:^(BOOL finished){
                            UITableViewCell *textFieldCell = (UITableViewCell*) [[self.activeTextField superview] superview];
                            NSIndexPath *textFieldIndexPath = [self.guestEntryTableView indexPathForCell:textFieldCell];
                            [self.guestEntryTableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
                        }];
    }

}

- (void)keyboardWillHide:(NSNotification*)notification {
    NSDictionary* userInfo = [notification userInfo];
    float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration: duration
                          delay: 0.0
                        options: (UIViewAnimationOptionBeginFromCurrentState)
                     animations:^{
                         self.guestEntryTableView.frame = _originalFrame;
                     }
                     completion:^(BOOL finished){
                         [self.guestEntryTableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
                     }];

}   

#pragma mark CGRect Utility function
CGRect IASKCGRectSwap(CGRect rect) {
    CGRect newRect;
    newRect.Origin.x = rect.Origin.y;
    newRect.Origin.y = rect.Origin.x;
    newRect.size.width = rect.size.height;
    newRect.size.height = rect.size.width;
    return newRect;
}

CGRect FixOriginRotation(CGRect rect, UIInterfaceOrientation orientation, int parentWidth, int parentHeight) {
    CGRect newRect;
    switch(orientation)
    {
        case UIInterfaceOrientationLandscapeLeft:
            newRect = CGRectMake(parentWidth - (rect.size.width + rect.Origin.x), rect.Origin.y, rect.size.width, rect.size.height);
            break;
        case UIInterfaceOrientationLandscapeRight:
            newRect = CGRectMake(rect.Origin.x, parentHeight - (rect.size.height + rect.Origin.y), rect.size.width, rect.size.height);
            break;
        case UIInterfaceOrientationPortrait:
            newRect = rect;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            newRect = CGRectMake(parentWidth - (rect.size.width + rect.Origin.x), parentHeight - (rect.size.height + rect.Origin.y), rect.size.width, rect.size.height);
            break;
    }
    return newRect;
}
2
Bob Spryn

Si votre UITableView est géré par une sous-classe de UITableViewController et non par UITableView et que le délégué de champ de texte est UITableViewController, il doit gérer automatiquement tout le défilement - tous ces autres commentaires sont très difficiles à implémenter dans la pratique.

Pour un bon exemple, voir l'exemple de projet Apple: TaggedLocations.

Vous pouvez voir qu'il défile automatiquement, mais aucun code ne semble le faire. Ce projet comporte également des cellules de vue de tableau personnalisées. Par conséquent, si vous construisez votre application avec ce guide, vous devriez obtenir le résultat souhaité.

1
shim

J'utilise ceux-ci et ils fonctionnent comme un charme:

BSKeyboardControls - BSKeyboardControls github

TPKeyboardAvoiding - TPKeyboardAvoiding github

1
Oskariagon

Je l'utilise souvent dans mes projets. Cette solution fonctionne avec les vues de défilement, les vues de table ou les vues de collection et est facile à configurer . Elle relie également automatiquement les boutons «Suivant» du clavier pour faire défiler les champs de texte.

Vérifiez-le ici

1
Cristina Sita

Une autre méthode facile (ne fonctionne qu'avec une section)

//cellForRowAtIndexPath
UItextField *tf;
[cell addSubview:tf];
tf.tag = indexPath.row;
tf.delegate = self;

//textFieldDidBeginEditing:(UITextField *)text
[[self.tableView scrollToRowsAtIndexPath:[NSIndexPath indexPathForRow:text.tag in section:SECTIONINTEGER] animated:YES];
1
JonasG

Petite variation avec Swift 4.2 ...

Sur UITableView, j’avais plusieurs sections mais je devais éviter l’effet d’en-tête flottant donc j’ai utilisé une approche "dummyViewHeight" comme on le voit quelque part ici sur Stack Overflow ... C’est donc mon solution pour ce problème (cela fonctionne aussi pour clavier + barre d'outils + suggestions):

Déclarez-la comme constante de classe:

let dummyViewHeight: CGFloat = 40.0

Ensuite

override func viewDidLoad() {
    super.viewDidLoad()
    //... some stuff here, not needed for this example

    // Create non floating header
    tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: dummyViewHeight))
    tableView.contentInset = UIEdgeInsets(top: -dummyViewHeight, left: 0, bottom: 0, right: 0)

    addObservers()
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    removeObservers()
}

Et voici toute la magie ...

@objc func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        let keyboardHeight = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as AnyObject).cgRectValue.size.height
        tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.bounds.size.width, height: dummyViewHeight))
        tableView.contentInset = UIEdgeInsets(top: -dummyViewHeight, left: 0, bottom: keyboardHeight, right: 0)
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.25) {
        self.tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.bounds.size.width, height: self.dummyViewHeight))
        self.tableView.contentInset = UIEdgeInsets(top: -self.dummyViewHeight, left: 0, bottom: 0, right: 0)
    }
}
1
DungeonDev

Solution facile et rapide.

Je viens de faire défiler vers la cellule droite chaque fois que le défilement se produit 

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView 

En supposant que je sais que la table est maintenant dans ce mode "_keepMyCellOnTop" & Je connais la cellule sélectionnée "_selectedCellIndex" ou fais défiler jusqu'à la cellule sélectionnée

- (void)scrollViewDidScroll:(UIScrollView *)scrollView 
{

    if (_keepMyCellOnTop)
    {
        [self.tableView scrollToRowAtIndexPath:_selectedCellIndex atScrollPosition:UITableViewScrollPositionTop animated:NO];
    }
}

Cela empêchera le défilement.

Placer le code dans -(void) scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView entraînera un défilement vers le haut et le bas 

1
judthedude

UITableViewController effectue le défilement automatiquement, en fait ... La différence par rapport à l'utilisation de UIViewController est que vous devez créer Navbar-Buttonitems par programme à l'aide de NavigationController, lorsque vous utilisez TableViewController.

1
Tom01

Je vais lancer ma solution (ou QuickDialog) dans le chapeau. En gros, attendez pour animer le défilement. Ce serait bien d’obtenir l’animation clavier JIT au lieu du nombre magique.

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    if (textField == self.emailTextField) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 50 * USEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
        });
    }
}
1
Steve Moser

Voici comment j'ai fait ce travail, qui est un mélange de réponses de Sam Ho et Marcel W, et de certaines de mes propres corrections de bugs apportées à mon code de merde. J'utilisais un UITableViewController. La table est maintenant redimensionnée correctement lorsque le clavier est affiché.

1) Dans viewDidLoad j'ai ajouté:

self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight;

2) J'avais oublié d'appeler les équivalents super dans viewWillAppear et awakeFromNib. J'ai ajouté ces derniers dans.

1
Danyal Aytekin

dans viewdidload

-(void)viewdidload{

[super viewdidload];

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

    -(void)keyboardWillChange:(NSNotification*)sender{

        NSLog(@"keyboardwillchange sender %@",sender);

float margin=0  // set your own topmargin


        CGFloat originY = [[sender.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].Origin.y;


        if (originY >= self.view.frame.size.height){

            NSLog(@"keyboardclose");



            [tb_ setFrame:CGRectMake(0, margin, self.view.frame.size.width, self.view.frame.size.height-margin)];

        }else{

            NSLog(@"keyobard on");

            float adjustedHeight = self.view.frame.size.height - margin - (self.view.frame.size.height-originY);

            [tb_ setFrame:CGRectMake(0, margin, self.view.frame.size.width, adjustedHeight)];
        }







    }
1
chings228

Regarde ma version :)

    - (void)keyboardWasShown:(NSNotification *)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = cellSelected.superview.frame;
    bkgndRect.size.height += kbSize.height;
    [cellSelected.superview setFrame:bkgndRect];
    [tableView setContentOffset:CGPointMake(0.0, cellSelected.frame.Origin.y-kbSize.height) animated:YES];
}


- (void)keyboardWasHidden:(NSNotification *)aNotification
{
    [tableView setContentOffset:CGPointMake(0.0, 0.0) animated:YES];
}
0
Pavel

Je pense que le meilleur moyen est d'utiliser UITableViewController. 

Si vous voulez une UITableView dans un UIViewController , créez simplement un ContentView avec un UITableViewController incorporé et placez les lignes suivantes dans le viedDidLoad de l'UIViewController:

self.tableView = ((UITableViewController*)self.childViewControllers[0]).tableView;
self.tableView.delegate = self;
self.tableView.dataSource = self;

Facile ;)

0
Ricardo Anjos

Je viens de découvrir un autre bogue lors de l'utilisation de UITableViewController. Il ne défilait pas automatiquement lorsque le clavier s’affichait. J'ai remarqué que c'était à cause de contentInsetAdjustmentBehavior = .never sur UITableView.

0
Rodrigo Manguinho

Voici ma solution inspirée de l'écran "Édition d'événement" de l'application Calendrier iOS7.

L'un des points clés de cette solution est que le clavier est désactivé lorsque l'utilisateur fait défiler le tableau.

La mise en oeuvre:

1) Ajouter une propriété qui stockera le champ de texte sélectionné:

@property (strong) UITextField *currentTextField;

et la variable BOOL que nous utiliserons pour vérifier s’il faut masquer le clavier lorsque l’utilisateur fait défiler le tableau.

BOOL hideKeyboardOnScroll;

2) Gestion des rappels de délégués UITextField:

#pragma mark - UITextFieldDelegate

- (void) textFieldDidBeginEditing: (UITextField *) textField {
    self.currentTextField = textField;
}

- (void) textFieldDidEndEditing: (UITextField *) textField {
    self.currentTextField = nil;
}

- (BOOL) textFieldShouldReturn: (UITextField *) textField {
   [textField resignFirstResponder];

    CGPoint newContentOffset = CGPointZero;
    if (tableView.contentSize.height > tableView.frame.size.height) {
        newContentOffset.y = MIN(tableView.contentOffset.y, tableView.contentSize.height - tableView.frame.size.height);
    }
    [tableView setContentOffset: newContentOffset animated: YES];

    return YES;
}

3) Gérez la méthode UIScrollViewDelegate pour vérifier la vue de défilement de cet utilisateur.

#pragma mark - UIScrollViewDelegate

- (void) scrollViewDidScroll: (UIScrollView *) scrollView {
    if (hideKeyboardOnScroll == YES) {
        [self.currentTextField resignFirstResponder];
    }
}

4) Abonnez-vous aux notifications de clavier dans la méthode [viewWillAppear] de viewcontroller et désabonnez-vous à la méthode [viewWillDisappear].

- (void) viewWillAppear: (BOOL) animated {
    [super viewWillAppear: animated];

    [ [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];

    [ [NSNotificationCenter defaultCenter] removeObserver: self name: UIKeyboardDidShowNotification object: nil];
    [ [NSNotificationCenter defaultCenter] removeObserver: self name: UIKeyboardWillHideNotification object: nil];    
}

5) Gérer les notifications du clavier:

- (void) keyboardWillShow: (NSNotification *) notification {
    CGRect keyboardFrame = [ [ [notification userInfo] objectForKey: UIKeyboardFrameBeginUserInfoKey] CGRectValue];

    // Find cell with textfield.
    CGRect textFieldFrame = [tableView convertRect: self.currentTextField.frame fromView: self.currentTextField];
    NSIndexPath *indexPath = [tableView indexPathForRowAtPoint: textFieldFrame.Origin];
    UITableViewCell *cell = [tableView cellForRowAtIndexPath: indexPath];
    //

    // Shrink tableView size.
    CGRect tableViewFrame = tableView.frame;
    tableView.frame = CGRectMake(tableView.frame.Origin.x, tableView.frame.Origin.y, tableView.frame.size.width,
                             self.view.frame.size.height - tableView.frame.Origin.y - keyboardFrame.size.height);
    //

    // Check if cell is visible in shrinked table size.
    BOOL cellIsFullyVisible = YES;
    if ( cell.frame.Origin.y < tableView.contentOffset.y ||
        (cell.frame.Origin.y + cell.frame.size.height) > (tableView.contentOffset.y + tableView.frame.size.height) ) {
        cellIsFullyVisible = NO;
    }
    //

    // If cell is not fully visible when scroll table to show cell;
    if (cellIsFullyVisible == NO) {
        CGPoint contentOffset = CGPointMake(tableView.contentOffset.x, CGRectGetMaxY(cell.frame) - tableView.frame.size.height);
        if (cell.frame.Origin.y < tableView.contentOffset.y) {
            contentOffset.y = cell.frame.Origin.y;
        }
        contentOffset.y = MAX(0, contentOffset.y);

        // For some reason [setContentOffset] is called without delay then
        // this code may not work for some cells. That why we call it with brief delay.
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [UIView animateWithDuration: 0.5 animations:^{
                [tableView setContentOffset: contentOffset animated: NO];
            } completion: ^(BOOL finished) {
                hideKeyboardOnScroll = YES;
            }];
        });
    } else {
        hideKeyboardOnScroll = YES;
    }
    //

    // Finally restore original table frame.
    tableView.frame = tableViewFrame;
    //
}

- (void) keyboardWillHide: (NSNotification *) notification {
    [super keyboardWillHide: notification];

    hideKeyboardOnScroll = NO;
}
0
Igor Kulagin

Je viens de regarder à nouveau dans la référence de la librairie iOS 5.0 et trouve cette section intitulée "Déplacement de contenu situé sous le clavier": TextAndWebiPhoneOS KeyboardManagement

Est-ce nouveau depuis iOS 5, peut-être? Je n'ai pas encore lu, car je suis au milieu de quelque chose d'autre, mais peut-être que d'autres en savent plus et peuvent m'éclairer ainsi que d'autres ici.

Le document Apple annule-t-il les éléments abordés ici ou les informations fournies ici sont-elles toujours utiles aux utilisateurs du SDK iOS 5?

0
Thomas Tempelmann

j'ai créé un petit projet qui résout ce problème avec le clavier. Dans mon cas, je n'ai qu'à faire en sorte que la vue de la table monte lorsque le clavier apparaît.

J'espère que cela t'aides!

http://git.io/BrH9eQ

0

Je pense qu'il n'y a pas de "bonne" façon de faire cela. Vous devez choisir la solution la mieux adaptée à votre cas d'utilisation. Dans mon application iPad, j'ai une UIViewController présentée comme modale sous la forme UIModalPresentationFormSheet et consistant en une UITableView. Cette table contient deux UITextFields par cellule. Le simple fait d'appeler scrollToRowAtIndexPath:atScrollPosition:animated: dans la méthode textFieldDidBeginEditing: ne fonctionne pas pour moi. J'ai donc créé une tableFooterView:

- (void)viewDidLoad
{
    [super viewDidLoad];

    m_footerView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, m_tableView.frame.size.width, 300.0f)];
    [m_footerView setBackgroundColor:[UIColor clearColor]];
    [m_tableView setTableFooterView:m_footerView];
    [m_footerView release];
}

L'idée est que le clavier cache la tableFooterView et non la UITextFields. Donc, la tableFooterView doit être suffisamment élevée. Après cela, vous pouvez utiliser scrollToRowAtIndexPath:atScrollPosition:animated: dans la méthode textFieldDidBeginEditing:.

Je pense qu'il est également possible d'afficher et de masquer la tableFooterView de manière dynamique en ajoutant les observateurs pour les notifications au clavier, mais je ne l'ai pas encore essayé:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

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

- (void)keyboardWillShow:(NSNotification *)notification 
{
     [m_tableView setTableFooterView:m_footerView];
}

- (void)keyboardWillHide:(NSNotification *)notification 
{
     [m_tableView setTableFooterView:nil];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
0
René Fischer

Solution pour Swift 3-4 avec animations et changement de cadre de clavier:

Tout d'abord, créez un Bool:

// MARK: - Private Properties
private var isKeyboardShowing = false

Deuxièmement, ajoutez des observateurs aux notifications du clavier système:

// MARK: - Overriding ViewController Life Cycle Methods
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: .UIKeyboardWillHide, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChangeFrame), name: .UIKeyboardWillChangeFrame, object: nil)
}

Troisièmement, préparez la fonction d’animation:

func adjustTableViewInsets(keyboardHeight: CGFloat, duration: NSNumber, curve: NSNumber){
    var extraHeight: CGFloat = 0
    if keyboardHeight > 0 {
        extraHeight = 20
        isKeyboardShowing = true
    } else {
        isKeyboardShowing = false
    }

    let contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight + extraHeight, right: 0)
    func animateFunc() {
        //refresh constraints
        //self.view.layoutSubviews()
        tableView.contentInset = contentInset
    }

    UIView.animate(withDuration: TimeInterval(duration), delay: 0, options: [UIViewAnimationOptions(rawValue: UInt(curve))], animations: animateFunc, completion: nil)
}

Ajoutez ensuite les méthodes cible/action (appelées par les observateurs):

// MARK: - Target/Selector Actions
func keyboardWillShow(notification: NSNotification) {
    if !isKeyboardShowing {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
            let keyboardHeight = keyboardSize.height

            let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
            let curve = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber

            adjustTableViewInsets(keyboardHeight: keyboardHeight, duration: duration, curve: curve)
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
    let curve = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber
    adjustTableViewInsets(keyboardHeight: 0, duration: duration, curve: curve)
}

func keyboardWillChangeFrame(notification: NSNotification) {
    if isKeyboardShowing {
        let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
        let curve = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber

        if let newKeyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            let keyboardHeight = newKeyboardSize.height
            adjustTableViewInsets(keyboardHeight: keyboardHeight, duration: duration, curve: curve)
        }
    }
}

Enfin, n'oubliez pas de supprimer les observateurs dans deinit ou dans viewWillDisappear:

deinit {
    NotificationCenter.default.removeObserver(self)
}
0
Jonathan Hoche
// scroll tableview so content ends at the middle of the tableview (out of the way of the keyboard)
CGPoint newContentOffset = CGPointMake(0, [self.tableView contentSize].height - (self.tableView.bounds.size.height / 2));
[self.tableView setContentOffset:newContentOffset animated:YES];
0
NuN

Pas besoin de calculs, utilisez le code ci-dessous, il fonctionnera:

override func viewDidLoad() {
super.viewDidLoad()

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}


func keyboardWillShow(_ notification:Notification) {

if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
    tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
}}


func keyboardWillHide(_ notification:Notification) {

if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
    tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
}}
0
Venkatesh G