Désactiver le défilement UIScrollView lorsque UITextField devient le premier répondeur

Lorsqu’un object UITextField , incorporé dans un UIScrollView devient le premier répondant, par exemple si l’utilisateur saisit un caractère, le UIScrollView défile automatiquement vers ce champ. Y a-t-il un moyen de le désactiver?

Dupliquer rdar: // 16538222 sur

S’appuyant sur la réponse de Moshe …

Sous-classe UIScrollView et remplacez la méthode suivante:

 - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated 

Laissez le vide Travail terminé!

J’ai eu le même problème et j’ai enfin trouvé une solution.

J’ai étudié la façon dont le défilement automatique est effectué en suivant la trace de l’appel et a constaté qu’un [UIFieldEditor scrollSelectionToVisible] est appelé lorsqu’une lettre est saisie dans UITextField . Cette méthode semble agir sur UIScrollView de l’ancêtre le plus proche de UITextField .

Ainsi, sur textFieldDidBeginEditing , en UITextField avec un nouvel UIScrollView de même taille (c’est-à-dire en insérant la vue entre UITextField et sa superview), cela bloquera le défilement automatique. Enfin, supprimez ce wrapper sur textFieldDidEndEditing .

Le code va comme:

 - (void)textFieldDidBeginEditing:(UITextField*)textField { UIScrollView *wrap = [[[UIScrollView alloc] initWithFrame:textField.frame] autorelease]; [textField.superview addSubview:wrap]; [textField setFrame:CGRectMake(0, 0, textField.frame.size.width, textField.frame.size.height)]; [wrap addSubview: textField]; } - (void)textFieldDidEndEditing:(UITextField*)textField { UIScrollView *wrap = (UIScrollView *)textField.superview; [textField setFrame:CGRectMake(wrap.frame.origin.x, wrap.frame.origin.y, wrap.frame.size.width, textField.frame.size.height)]; [wrap.superview addSubview:textField]; [wrap removeFromSuperview]; } 

J’espère que cela t’aides!

J’ai eu le même problème avec la désactivation du défilement automatique d’un UITextView étant une cellule de UITableView . J’ai pu résoudre le problème en utilisant l’approche suivante:

 @interface MyTableViewController : UITableViewController @implementation MyTableViewController { BOOL preventScrolling; // ... } // ... set self as the delegate of the text view - (void)textViewDidBeginEditing:(UITextView *)textView { preventScrolling = YES; } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (preventScrolling) { [self.tableView setContentOffset:CGPointMake(0, -self.tableView.contentInset.top) animated:NO]; } } - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { preventScrolling = NO; } 

La définition de scrollViewWillBeginDragging est utilisée pour restaurer le comportement de défilement par défaut lorsque l’utilisateur lance lui-même le défilement.

Comme Taketo l’a mentionné, lorsqu’un premier object UITextField est rendu premier répondeur, sa première vue parent de type UIScrollView (s’il en existe un) est défilée pour rendre UITextField visible. Le plus simple consiste à envelopper simplement chaque UITextField dans un UIScrollView (ou, idéalement, à les envelopper dans un seul UIScrollView factice). Ceci est très similaire à la solution de Taketo, mais cela devrait vous donner des performances légèrement supérieures, et cela gardera votre code (ou votre interface dans Interface Builder) beaucoup plus propre à mon avis.

Il semble que UIScrollview, qui contient UITextfield, ajuste automatiquement son décalage de contenu; quand textfield va devenir le premier intervenant. Cela peut être résolu en ajoutant d’abord un champ de texte dans une vue de défilement de même taille, puis en l’ajoutant à la vue de défilement principale. au lieu d’append directement à la vue de défilement principale

  // Swift let rect = CGRect(x: 0, y: 0, width: 200, height: 50) let txtfld = UITextField() txtfld.frame = CGRect(x: 0, y: 0, width: rect.width, height: rect.height) let txtFieldContainerScrollView = UIScrollView() txtFieldContainerScrollView.frame = rect txtFieldContainerScrollView.addSubview(txtfld) // Now add this txtFieldContainerScrollView in desired UITableViewCell, UISCrollView.. etc self.mainScrollView.addSubview(txtFieldContainerScrollView) // Am33T 

En s’appuyant sur la réponse de Luke, pour résoudre le problème que sa solution désactive complètement le défilement automatique, vous pouvez le désactiver de la manière suivante:

 // TextFieldScrollView #import  @interface TextFieldScrollView : UIScrollView @property (assign, nonatomic) IBInspectable BOOL preventAutoScroll; @end @implementation TextFieldScrollView - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated { if (self.preventAutoScroll == NO) { [super scrollRectToVisible:rect animated:animated]; } } @end 

De cette façon, vous pouvez le configurer complètement dans Interface Builder pour désactiver le défilement automatique, mais vous avez le contrôle total à tout moment pour le réactiver (même si vous le souhaitez).

C’est comme ça que je le fais:

C’est très simple, vous devez retourner votre propre contentOffset pour tout scrollRectToVisible.

De cette façon, vous ne nuisez pas au comportement normal et au stream de choses – il suffit de fournir les mêmes fonctionnalités dans le même canal, avec vos propres améliorations.

 #import  @protocol ExtendedScrollViewDelegate  - (CGPoint)scrollView:(UIScrollView*)scrollView offsetForScrollingToVisibleRect:(CGRect)rect; @end @interface ExtendedScrollView : UIScrollView @property (nonatomic, unsafe_unretained) id scrollToVisibleDelegate; @end #import "ExtendedScrollView.h" @implementation ExtendedScrollView - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated { if (_scrollToVisibleDelegate && [_scrollToVisibleDelegate respondsToSelector:@selector(scrollView:offsetForScrollingToVisibleRect:)]) { [self setContentOffset:[_scrollToVisibleDelegate scrollView:self offsetForScrollingToVisibleRect:rect] animated:animated]; } else { [super scrollRectToVisible:rect animated:animated]; } } @end 

J’ai essayé la réponse de @ TaketoSano, mais cela ne semble pas fonctionner. Mon cas est que je n’ai pas de scrollview, juste une vue avec plusieurs champs de texte.

Et enfin, j’ai une solution de contournement. Il y a deux noms de notification par défaut pour le clavier dont j’ai besoin:

  • UIKeyboardDidShowNotification lorsque le clavier a été UIKeyboardDidShowNotification ;
  • UIKeyboardWillHideNotification lorsque le clavier se cache.

Voici l’exemple de code que j’ai utilisé:

 - (void)viewDidLoad { [super viewDidLoad]; ... NSNotificationCenter * notificationCetner = [NSNotificationCenter defaultCenter]; [notificationCetner addObserver:self selector:@selector(_keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; [notificationCetner addObserver:self selector:@selector(_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } - (void)_keyboardWasShown:(NSNotification *)note { [self.view setFrame:(CGRect){{272.f, 55.f}, {480.f, 315.f}}]; } - (void)_keyboardWillHide:(NSNotification *)note { [self.view setFrame:(CGRect){{272.f, 226.5f}, {480.f, 315.f}}]; } 

Ici, le (CGRect){{272.f, 226.5f}, {480.f, 315.f}} est l’image par défaut de la vue lorsque le clavier est masqué. Et (CGRect){{272.f, 55.f}, {480.f, 315.f}} est l’image de la vue lorsque le clavier est (CGRect){{272.f, 55.f}, {480.f, 315.f}} .

Et maintenant, le changement de cadre de la vue sera appliqué automatiquement à l’animation, c’est vraiment parfait!

J’ai une vue de collection avec un champ de texte tout en haut, imitant le UITableView.tableHeaderView . Ce champ de texte est situé dans l’espace de décalage du contenu négatif afin qu’il n’interfère pas avec le rest de la vue de collection. Je suis fondamentalement en train de détecter si l’utilisateur effectue ou non le défilement dans la vue de défilement et si le champ de texte est le premier répondeur et si la vue de défilement défile au-dessus de l’encart de contenu de la vue de défilement. Ce code exact n’aidera forcément personne mais il pourra le manipuler pour qu’il corresponde à son cas.

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { // This is solving the issue where making the text field first responder // automatically scrolls the scrollview down by the height of the search bar. if (!scrollView.isDragging && !scrollView.isDecelerating && self.searchField.isFirstResponder && (scrollView.contentOffset.y < -scrollView.contentInset.top)) { [scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, -scrollView.contentInset.top) animated:NO]; } } 

Je ne connais aucune propriété de UIScrollView qui permettrait cela. Ce serait une expérience utilisateur médiocre que de pouvoir désactiver cela, à mon humble avis.

Cela dit, il est possible de sous- UIScrollView et de remplacer certaines de ses méthodes pour vérifier que UITextfield n’est pas un premier intervenant avant le défilement.

Un moyen plus simple d’arrêter le défilement de défilement lorsque vous sélectionnez un textField est dans votre viewController :: viewWillAppear () NE PAS appeler [super viewWillAppear];

Vous pouvez alors contrôler le défilement comme vous le souhaitez.