web-dev-qa-db-fra.com

UIScrollView ajuste contentOffset lorsque contentSize change

J'ajuste l'état d'un contrôleur de vue de détail, juste avant qu'il soit poussé sur une navigationController:

[self.detailViewController detailsForObject:someObject];
[self.navigationController pushViewController:self.detailViewController
                                     animated:YES];

Dans la DetailViewController un scrollView réside. Quel contenu je redimensionne en fonction de l'objet transmis:

- (void)detailsForObject:(id)someObject {
    // set some textView's content here
    self.contentView.frame = <rect with new calculated size>;

    self.scrollView.contentSize = self.contentView.frame.size;
    self.scrollView.contentOffset = CGPointZero;
}

Maintenant, tout cela fonctionne, mais scrollView ajuste sa valeur contentOffset lors de l’animation par insertion du navigateurContrôleur. La contentOffset sera définie sur la différence entre le dernier contentSize et le nouveau calculé. Cela signifie que la deuxième fois que vous ouvrez le detailsView, les détails défileront vers un emplacement indésirable. Même si je règle la contentOffset sur CGPointZero explicitement.

J'ai constaté que la réinitialisation de la contentOffset dans - viewWillAppear n'a aucun effet. Le mieux que je puisse faire est de réinitialiser le contentOffset dans viewDidAppear, ce qui provoque un mouvement de haut en bas notable du contenu:

- (void)viewDidAppear:(BOOL)animated {
    self.scrollView.contentOffset = CGPointZero;
}

Existe-t-il un moyen d'empêcher une UIScrollView d'ajuster sa contentOffset lorsque sa contentSize est modifiée?

36
Berik

Se produit lors du transfert d'une UIViewController contenant une UIScrollView à l'aide d'une UINavigationController.

IOS 7 

_ {Solution 1 (Code)} _

Définissez @property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets sur NO.

_ {Solution 2 (Storyboard))

Décocher le Adjust Scroll View Insets 

Adjust Scroll View Insets

iOS 6

Solution (Code)} _

Définissez les propriétés UIScrollView de contentOffset et contentInset dans viewWillLayoutSubviews. Exemple de code:

- (void)viewWillLayoutSubviews{
  [super viewWillLayoutSubviews];
  self.scrollView.contentOffset = CGPointZero;
  self.scrollView.contentInset = UIEdgeInsetsZero;
}
58
KarenAnne

La cause de ce problème reste incertaine, bien que j'ai trouvé une solution. En réinitialisant la taille du contenu et le décalage avant de les ajuster, UIScrollView ne s'animera pas:

- (void)detailsForObject:(id)someObject {
    // These 2 lines solve the issue:
    self.scrollView.contentSize = CGSizeZero;
    self.scrollView.contentOffset = CGPointZero;

    // set some textView's content here
    self.contentView.frame = <rect with new calculated size>;

    self.scrollView.contentSize = self.contentView.frame.size;
    self.scrollView.contentOffset = CGPointZero;
}
15
Berik

J'ai eu le même problème avec un UIScrollview, où le problème était causé par la non définition de contentSize. Après avoir défini contentSize sur le nombre d'éléments, ce problème a été résolu.

self.headerScrollView.mainScrollview.contentSize = CGSizeMake(320 * self.sortedMaterial.count, 0);
2
Antoine

Voici ce qui a fonctionné pour moi:
Dans le storyboard, dans l'inspecteur de taille de scrollView, définissez le comportement de réglage des encarts de contenu sur "Jamais".

 enter image description here

1
Eden

J'ai rencontré le problème et, dans un cas précis - je ne modifie pas la taille - j'ai utilisé les éléments suivants:

float position = 100.0;//for example

SmallScroll.center = CGPointMake(position + SmallScroll.frame.size.width / 2.0, SmallScroll.center.y);

Idem fonctionnerait avec y: anotherPosition + SmallScroll.frame.size.height / 2.0

Donc, si vous n'avez pas besoin de redimensionner, c'est une solution rapide et sans douleur.

0
Balázs Csordás

Je rencontrais un problème similaire, où UIKit définissait le contentOffset de mon scrollView lors des animations Push.

Aucune de ces solutions ne fonctionnait pour moi, peut-être parce que je prenais en charge iOS 10 et iOS 11.

J'ai pu résoudre mon problème en sous-classant mon scrollview pour empêcher UIKit de modifier mes décalages une fois que le scrollview avait été supprimé de la fenêtre:

/// A Scrollview that only allows the contentOffset to change while it is in the window hierarchy. This can keep UIKit from resetting the `contentOffset` during transitions, etc.
class LockingScrollView: UIScrollView {
    override var contentOffset: CGPoint {
        get {
            return super.contentOffset
        }
        set {
            if window != nil {
                super.contentOffset = newValue
            }
        }
    }
}
0
Slimebaron

ScrollView est-il la vue racine du DetailViewController? Si c'est le cas, essayez d'encadrer scrollView dans une UIView plaine et faites de cette dernière la vue racine de DetailViewController. Étant donné que UIViews n'a pas de propriété contentOffset, ils sont immunisés contre les réglages de décalage de contenu effectués par le contrôleur de navigation (en raison de la barre de navigation, etc.).

0
octy