web-dev-qa-db-fra.com

Désactivation du défilement automatique de UITableView lors de l'édition de UITextField dans UITableViewCell

J'utilise custom UITableViewCells dans ma UITableView. Chacune de ces UITableViewCells est assez élevée et contient une UITextField au sommet.

Lorsqu'un utilisateur appuie sur la UITextField pour la modifier, un clavier apparaît et la UITableView défile automatiquement de sorte que la cellule se trouve en haut de l'écran. 

Le problème est que cela fait défiler la UITableView vers le bas de la UITableViewCell, pas vers le haut. Lorsque la UITableViewCell est élevée et modifiée, la UITextField est en haut de sorte que vous ne pouvez pas voir la UITextField. Je sais comment faire défiler la UITableView par programme, mais je ne sais pas comment désactiver ce défilement automatique pour pouvoir faire défiler la UITableView par moi-même. Comment puis-je faire ceci?

47
animal_chin

Le comportement de défilement automatique est situé dans la fonctionnalité UITableViewController.

Pour désactiver le défilement automatique, j'ai trouvé deux méthodes:

  1. Utilisez au lieu de UITableViewController simplement un UIViewController - définissez vous-même la source de données et le délégué.
  2. Remplacez la méthode viewWillAppear et n'appelez pas [super viewWillAppear: animated]

Avec les deux solutions, vous désactivez non seulement le défilement automatique, mais également certaines autres fonctionnalités intéressantes, mais non essentielles, décrites dans la présentation de la référence de classe d’Apple:

https://developer.Apple.com/documentation/uikit/uitableviewcontroller

63
Dominic Sander

Définissez les propriétés de votre UITableViewController:

@property (nonatomic) BOOL scrollDisabled;
@property (nonatomic) CGFloat lastContentOffsetY;

Avant d'appeler becomeFirstResponder:

// Save the table view's y content offset 
lastContentOffsetY = tableViewController.tableView.contentOffset.y;
// Enable scrollDisabled
scrollDisabled = YES;

Ajoutez le code suivant à votre contrôleur de vue de table:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (self.scrollDisabled) {
        [self.tableView setContentOffset:CGPointMake(0, lastContentOffsetY)];
    }
    ...
}

Après avoir appelé resignFirstResponder, définissez scrollDisabled = NO.

7
william-yang

Vous pouvez faire ce qui suit:

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification object:nil];

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

- (void)unregisterForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil];
}

- (void)keyboardWillShow:(NSNotification *)notification
{
    self.tableView.scrollEnabled = NO;
}

- (void)keyboardDidShow:(NSNotification *)notification
{
    double delayInSeconds = 0.3;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            self.tableView.scrollEnabled = YES;
    });
}

Puis implémentez cette méthode UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (! self.tableView.scrollEnabled)
        [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
}

!!! Mais soyez averti que si l'utilisateur appuie sur un emplacement du champ UITextField qui sera couvert par le clavier, il ne défilera pas.

De mon point de vue, la meilleure chose à faire est de s'assurer que toutes les cellules de haut en bas, l'une avec le UITextField inclus, seront visibles lorsque le clavier affichera.

3
arturgrigor

Le problème pour moi n’était pas tant de faire défiler le texte que de faire défiler l’écran texte hors de l’écran.

Ainsi, au lieu d’empêcher le défilement, je ne fais que réinscrire la vue tableau à l’endroit où je veux lorsque la modification est déclenchée, comme ceci:

public func textViewShouldBeginEditing(textView: UITextView) -> Bool {            
  dispatch_async(dispatch_get_main_queue()) {
    tableViewController.tableView.scrollToRowAtIndexPath(self.indexPath!, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)
  }
  return true
}
1
infinite-loop

Malheureusement, la substitution de -viewWillAppear: ne fonctionne pas pour moi dans iOS 8.

Voici ma solution (comme dans l'implémentation UITableViewController):

- (void)viewDidLoad {

[super viewDidLoad];

[[NSNotificationCenter defaultCenter] removeObserver:self.tableView name:UIKeyboardWillShowNotification object:nil];

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

Étant donné que le comportement de défilement automatique est invoqué par les notifications d’affichage/masquage de UIKeyboard, ne les observez donc pas.

1
keyOfVv

La meilleure méthode consiste à sous-classer UITableView, puis à remplacer setContentOffset(_ contentOffset: CGPoint, animated: Bool) et à ne pas appeler super.setContentOffset(_ contentOffset: CGPoint, animated: Bool). Dans cette méthode, le contrôleur de vue effectue le défilement automatique.

override func setContentOffset(_ contentOffset: CGPoint, animated: Bool)
{
    //Do nothing
}
1
juanelomx