web-dev-qa-db-fra.com

Obtenez UITableView pour faire défiler jusqu'au champ UITextField sélectionné et éviter d'être caché par le clavier

J'ai un UITextField dans une vue de table sur un UIViewController (pas un UITableViewController). Si la vue du tableau est sur un UITableViewController, le tableau défilera automatiquement jusqu'au textField en cours de modification pour éviter qu'il ne soit masqué par le clavier. Mais sur un UIViewController ce n'est pas le cas.

J'ai essayé pendant quelques jours de lire plusieurs façons d'essayer d'accomplir cela et je ne peux pas le faire fonctionner. La chose la plus proche qui défile est:

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

// SUPPOSEDLY Scroll to the current text field

CGRect textFieldRect = [textField frame];
[self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];

}

Cependant, cela fait uniquement défiler le tableau jusqu'à la ligne supérieure. Ce qui semble être une tâche facile a été quelques jours de frustration.

J'utilise ce qui suit pour construire les cellules tableView:

- (UITableViewCell *)tableView:(UITableView *)aTableView
    cellForRowAtIndexPath:(NSIndexPath *)indexPath {

NSString *identifier = [NSString stringWithFormat: @"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]];

UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier];

    if (cell == nil) {

        cell = [[[UITableViewCell alloc] 
        initWithStyle:UITableViewCellStyleDefault 
        reuseIdentifier:identifier] autorelease];

        cell.accessoryType = UITableViewCellAccessoryNone;

        UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];

        theTextField.adjustsFontSizeToFitWidth = YES;
        theTextField.textColor = [UIColor redColor];
        theTextField.text = [textFieldArray objectAtIndex:indexPath.row];
        theTextField.keyboardType = UIKeyboardTypeDefault;
        theTextField.returnKeyType = UIReturnKeyDone;
        theTextField.font = [UIFont boldSystemFontOfSize:14];
        theTextField.backgroundColor = [UIColor whiteColor];
        theTextField.autocorrectionType = UITextAutocorrectionTypeNo;
        theTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
        theTextField.clearsOnBeginEditing = NO;
        theTextField.textAlignment = UITextAlignmentLeft;

        //theTextField.tag = 0;
        theTextField.tag=indexPath.row;

        theTextField.delegate = self;

        theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
        [theTextField setEnabled: YES];

        [cell addSubview:theTextField];

        [theTextField release];


}

return cell;
}

Je soupçonne que je peux faire défiler correctement la tableView si je peux en quelque sorte passer le indexPath.row dans la méthode textFieldDidBeginEditing?

Toute aide est appréciée.

46
Lauren Quantrell

Dans mon application, j'ai utilisé avec succès une combinaison de contentInset et scrollToRowAtIndexPath comme ceci:

Lorsque vous souhaitez afficher le clavier, ajoutez simplement un contentInset en bas avec votre table avec la hauteur souhaitée:

tableView.contentInset =  UIEdgeInsetsMake(0, 0, height, 0);

Ensuite, vous pouvez utiliser en toute sécurité

[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:cell_index inSection:cell_section] animated:YES];

En ajoutant contentInset, même si vous vous concentrez sur la dernière cellule, la tableView pourra toujours défiler. Assurez-vous simplement que lorsque vous fermez le clavier, vous réinitialisez le contentInset.

MODIFIER:
Si vous n'avez qu'une seule section (vous pouvez remplacer cell_section avec 0) et utilisez la balise textView pour informer la ligne de cellule.

Vérifiez cela pour faites défiler UITextField au-dessus du clavier dans un UITableView OR UIScrollView

108
Andrei Stanescu
- (void)keyboardWillShow:(NSNotification *)sender
{
    CGFloat height = [[sender.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
    NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
        UIEdgeInsets edgeInsets = UIEdgeInsetsMake(0, 0, height, 0);
        tableView.contentInset = edgeInsets;
        tableView.scrollIndicatorInsets = edgeInsets;
    } completion:nil];
}

- (void)keyboardWillHide:(NSNotification *)sender
{
    NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
        UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
        tableView.contentInset = edgeInsets;
        tableView.scrollIndicatorInsets = edgeInsets;
    } completion:nil];
}

Et dans - (void) viewDidLoad

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

Ensuite

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

Ceci est un tweak à la réponse de FunkyKat (grand merci FunkyKat!). Il serait probablement avantageux de ne pas coder en dur UIEdgeInsetsZero pour une future compatibilité iOS.

Au lieu de cela, je demande la valeur d'encart actuelle et ajustez la valeur inférieure selon les besoins.

- (void)keyboardWillShow:(NSNotification *)sender {
    CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.height : kbSize.width;
    if (isIOS8()) height = kbSize.height;

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = [[self tableView] contentInset];
        edgeInsets.bottom = height;
        [[self tableView] setContentInset:edgeInsets];
        edgeInsets = [[self tableView] scrollIndicatorInsets];
        edgeInsets.bottom = height;
        [[self tableView] setScrollIndicatorInsets:edgeInsets];
    }];
}

- (void)keyboardWillHide:(NSNotification *)sender {
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = [[self tableView] contentInset];
        edgeInsets.bottom = 0;
        [[self tableView] setContentInset:edgeInsets];
        edgeInsets = [[self tableView] scrollIndicatorInsets];
        edgeInsets.bottom = 0;
        [[self tableView] setScrollIndicatorInsets:edgeInsets];
    }];
}
10
bmauter

Pour le bien de toute autre personne rencontrant ce problème, je publie les méthodes nécessaires ici:

- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    NSString *identifier = [NSString stringWithFormat: @"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]];

    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier];

    if (cell == nil) {

        cell = [[[UITableViewCell alloc]  initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];

        UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];

        theTextField.keyboardType = UIKeyboardTypeDefault;
        theTextField.returnKeyType = UIReturnKeyDone;
        theTextField.clearsOnBeginEditing = NO;
        theTextField.textAlignment = UITextAlignmentLeft;

        // (The tag by indexPath.row is the critical part to identifying the appropriate
        // row in textFieldDidBeginEditing and textFieldShouldEndEditing below:)

        theTextField.tag=indexPath.row;

        theTextField.delegate = self;

        theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
        [theTextField setEnabled: YES];

        [cell addSubview:theTextField];

        [theTextField release];

    }

    return cell;
}

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

    int z = textField.tag;                                              

    if (z > 4) {

        // Only deal with the table row if the row index is 5 
        // or greater since the first five rows are already 
        // visible above the keyboard   

        // resize the UITableView to fit above the keyboard

        self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,200.0);       

        // adjust the contentInset

        wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10);        

        // Scroll to the current text field

        [wordsTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:z inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];

    }
}


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

    // Determine which row is being edited

    int z = textField.tag;  

    if (z > 4) {

        // resize the UITableView to the original size

        self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,416.0);       

        // Undo the contentInset
        wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);         

    }

    return YES;

}

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

    // Dismisses the keyboard when the "Done" button is clicked

    [textField resignFirstResponder];

    return YES;                                 

}
8
Lauren Quantrell

Essayez mon codage, cela vous aidera

tabelview.contentInset =  UIEdgeInsetsMake(0, 0, 210, 0);
[tableview scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:your_indexnumber inSection:Your_section]
                 atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
1
vinothsivanandam

J'avais besoin d'une solution simple donc pour moi aidé :

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        let pointInTable = textField.superview!.convert(textField.frame.Origin, to: tableView)
        var tableVContentOffset = tableView.contentOffset
        tableVContentOffset.y = pointInTable.y
        if let accessoryView = textField.inputAccessoryView {
            tableVContentOffset.y -= accessoryView.frame.size.height
        }
        tableView.setContentOffset(tableVContentOffset, animated: true)
        return true;
    }

enter image description here

1
Nik Kov

Apple a un article officiel expliquant comment le faire naturellement comme dans UITableViewController. Ma réponse Stackoverflow explique cela avec une Swift.

https://stackoverflow.com/a/31869898/1032179

1
Salman Hasrat Khan

Mon code. Peut-être que quelqu'un sera utile: cellule textField personnalisée dans tableView

.m

    @property (nonatomic, strong) UITextField *currentCellTextField;

       CustomCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
            if (cell == nil) {
                NSArray * nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
                cell = (CustomCell *)[nib objectAtIndex:0];
                cell.textfield.delegate = self;
            }
      - (void) textFieldDidBeginEditing:(UITextField *)textField
 {
  self.currentCellTextField = textField;

  CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.Origin fromView:textField];
  NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt];

if (path.section >= 2) {
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3];
    self.organisationTableView.contentInset = UIEdgeInsetsMake(0, 0, kOFFSET_FOR_KEYBOARD, 0);
    CGPoint siize = self.organisationTableView.contentOffset;
    siize.y =(pnt.y-170);
    self.organisationTableView.contentOffset = CGPointMake(0, siize.y);
    [UIView commitAnimations];
    }
 }

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

CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.Origin fromView:textField];
NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt];

 if (path.section >= 2) {
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3];
    self.organisationTableView.contentInset = UIEdgeInsetsZero;
    self.organisationTableView.contentOffset = CGPointMake(0, self.organisationTableView.contentOffset.y);
    [UIView commitAnimations];
      }

 return YES;
   }
0
Vadim Shevchik

Dans mon cas, mon UITableview était dans un autre UIView et que UIvie était dans le UIScrollview principal. J'ai donc utilisé une solution plus générale pour ce genre de problèmes. J'ai simplement trouvé la coordonnée Y de ma cellule dans l'UIScrollView spécifique, puis j'ai défilé jusqu'au point correct:

-(void)textFieldDidBeginEditing:(UITextField *)textField{
float kbHeight = 216;//Hard Coded and will not support lanscape mode
UITableViewCell *cell = (UITableViewCell *)[textField superview];
float scrollToHeight = [self FindCordinate:cell];
[(UIScrollView *)self.view setContentOffset:CGPointMake(0, scrollToHeight - kbHeight + cell.frame.size.height) animated:YES];
}

-(float)FindCordinate:(UIView *)cell{
float Ycordinate = 0.0;
while ([cell superview] != self.view) {
    Ycordinate += cell.frame.Origin.y;
    cell = [cell superview];
}
Ycordinate += cell.frame.Origin.y;
return Ycordinate;
}
0
Mike.R

Vous pouvez essayer d'ajouter un UITableViewController au UIViewController au lieu d'une simple vue de table. De cette façon, vous pouvez appeler viewWillAppear de UITableViewController et tout semblera fonctionner.

Exemple:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [tableViewController viewWillAppear:animated];
}
0
colin lamarre

Une autre solution simple consiste à ajouter un espace supplémentaire pour le pied de page de la dernière section du tableau:

- (float)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
    if (section == lastSection) {
        return keyboard height;
    }
    return 0;
}

Nous pouvons également ajouter notre icône dans cette zone. :)

0
thanhbinh84

J'ai ajouté une petite fonctionnalité aux réponses @FunkyKat et @bmauter (excellente réponse au fait, ce devrait être celle acceptée)

Les encarts réguliers de Table View Edge sont conservés, avant/après l'apparition du clavier.

- (void)keyboardWillShow:(NSNotification *)sender
{
    CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = self.tableView.contentInset;
        edgeInsets.bottom += height;
        self.tableView.contentInset = edgeInsets;
        edgeInsets = self.tableView.scrollIndicatorInsets;
        edgeInsets.bottom += height;
        self.tableView.scrollIndicatorInsets = edgeInsets;
    }];
}

- (void)keyboardWillHide:(NSNotification *)sender
{
    CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height;

    [UIView animateWithDuration:duration animations:^{
        UIEdgeInsets edgeInsets = self.tableView.contentInset;
        edgeInsets.bottom -= height;
        self.tableView.contentInset = edgeInsets;
        edgeInsets = self.tableView.scrollIndicatorInsets;
        edgeInsets.bottom -= height;
        self.tableView.scrollIndicatorInsets = edgeInsets;
    }];
}
0
Thomas Besnehard

Vous devez redimensionner le tableView lui-même afin qu'il ne passe pas sous le clavier.

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

// SUPPOSEDLY Scroll to the current text field
self.worldsTableView.frame = CGRectMake(//make the tableView smaller; to only be in the area above the keyboard);
CGRect textFieldRect = [textField frame];
[self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];

}

Vous pouvez également utiliser une notification au clavier; cela fonctionne légèrement mieux car vous avez plus d'informations et est plus cohérent en termes de savoir quand le clavier arrive:

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

Et puis implémentez:

- (void)keyboardWillShow:(NSNotification *)notification {

}
- (void)keyboardWillHide:(NSNotification *)notification {

}
0
GendoIkari