Quand un UITextField
, incorporé dans un UIScrollView
devient premier répondant, disons que l'utilisateur qui tape un caractère, le UIScrollView
défile automatiquement vers ce champ, existe-t-il un moyen de le désactiver?
S'appuyant sur la réponse de Moshe ...
Sous-classe UIScrollView et substituer la méthode suivante:
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
Laissez le vide. Travail accompli!
Je suis aux prises avec le même problème et j'ai enfin trouvé une solution.
J'ai étudié comment le défilement automatique est effectué en suivant la trace des appels et découvert qu'un [UIFieldEditor scrollSelectionToVisible]
interne est appelé lorsqu'une lettre est saisie dans la variable UITextField
. Cette méthode semble agir sur la UIScrollView
de l'ancêtre le plus proche de la UITextField
.
Ainsi, sur textFieldDidBeginEditing
, en encapsulant la UITextField
avec une nouvelle UIScrollView
de même taille (c'est-à-dire, l'insertion de la vue entre la UITextField
et sa superview), cela bloquera le défilement automatique. Enfin, supprimez cette enveloppe 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'une UITextView
étant une cellule de UITableView
. J'ai pu résoudre le problème en utilisant l'approche suivante:
@interface MyTableViewController : UITableViewController<UITextViewDelegate>
@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;
}
Définir scrollViewWillBeginDragging
est utilisé 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 UITextField
est créé en tant que premier répondant, sa première vue parent de type UIScrollView
(s'il en existe un) fait défiler l'écran pour rendre visible cette UITextField
. Le plus simple consiste à envelopper chaque UITextField dans une UIScrollView
(ou, idéalement, dans un seul dummy UIScrollView
). Ceci est très similaire à la solution de Taketo, mais cela devrait vous donner des performances légèrement meilleures, et cela gardera votre code (ou votre interface dans Interface Builder) beaucoup plus propre à mon avis.
Il ressemble à UIScrollview qui contient UITextfield, ajuste automatiquement son contenu de décalage; quand textfield va devenir le premier intervenant . Cela peut être résolu en ajoutant textfield dans scrollview de même taille, puis en ajoutant à la vue de défilement principale. au lieu d'ajouter directement à scrollview principal
// 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 vous appuyant sur la réponse de Luke, pour résoudre le problème suivant: sa solution désactive complètement le défilement automatique, vous pouvez le désactiver sélectivement comme suit:
// TextFieldScrollView
#import <UIKit/UIKit.h>
@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 configurer complètement Interface Builder pour désactiver le défilement automatique, tout en ayant le contrôle total à tout moment pour le réactiver (bien que la raison de votre choix me dépasse).
C'est comme ça que je le fais:
C’est très simple, vous devez renvoyer votre propre contentOffset pour n’importe quel scrollRectToVisible.
De cette façon, vous ne nuisez pas au comportement normal ni à la fluidité des choses - vous fournissez simplement les mêmes fonctionnalités dans le même canal, avec vos propres améliorations.
#import <UIKit/UIKit.h>
@protocol ExtendedScrollViewDelegate <NSObject>
- (CGPoint)scrollView:(UIScrollView*)scrollView offsetForScrollingToVisibleRect:(CGRect)rect;
@end
@interface ExtendedScrollView : UIScrollView
@property (nonatomic, unsafe_unretained) id<ExtendedScrollViewDelegate> 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 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 de contenu négatif afin qu'il n'interfère pas avec le reste de la vue de collection. En gros, je détecte si l'utilisateur effectue 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-delà du haut de son contenu. Ce code exact n’aidera pas nécessairement tout le monde, mais ils pourront le manipuler pour s’adapter à leur 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];
}
}
J'ai essayé la réponse de @ TaketoSano, mais cela ne semble pas fonctionner. Mon cas est que je n'ai pas de vue de défilement, mais seulement une vue avec plusieurs champs de texte.
Et finalement, j'ai une solution de contournement. Il y a deux noms de notification par défaut pour le clavier dont j'ai besoin:
UIKeyboardDidShowNotification
quand le clavier a montré; UIKeyboardWillHideNotification
quand le clavier va se cacher.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 le cadre par défaut de la vue lorsque le clavier est masqué. Et (CGRect){{272.f, 55.f}, {480.f, 315.f}}
est le cadre de la vue lorsque le clavier est affiché.
Et b.t.w., le changement d'image de la vue sera automatiquement appliqué à l'animation, c'est vraiment parfait!
Je ne connais aucune propriété de UIScrollView
qui le permettrait. Ce serait une mauvaise expérience utilisateur de pouvoir désactiver cela, à mon humble avis.
Cela dit, il peut être possible de sous-classer UIScrollView
et de remplacer certaines de ses méthodes pour vérifier que la UITextfield
n'est pas un premier intervenant avant le défilement.