40 votes

Décalage incorrect de UIScrollView avec la mise en page automatique

J'ai un assez simple point de vue de la configuration:

Un UIViewController, avec un enfant UIScrollView et UIImageView dans cette UIScrollView. J'ai mis l' UIImageView , avec une hauteur suffisante pour sortir de la zone visible (c'est à dire. plus d' 1024pt), et de définir l' Bottom space to superview de la contrainte de mon UIImageView à une valeur positive (20 par exemple).

project layout

L'ensemble de l'installation fonctionne comme prévu, l'image défile bien dans son parent. Sauf lors de l'affichage défile à l'écran (l'effet est plus visible si vous défiler vers le bas de l'écran), puis de disparaître, et apparaît à nouveau (vous êtes passé à un autre point de vue et est venu en arrière), le défilement de la valeur est restaurée, mais le contenu de défilement de la vue est déplacée à l'extérieur de la partie supérieure de la vue parente.

Ce n'est pas simple à expliquer, je vais essayer de le dessiner: visual representation of previous paragraph

Si vous voulez tester/afficher la source (ou la table de montage, je n'ai pas modifier une seule ligne de code). J'ai mis un peu de démo sur mon github: https://github.com/guillaume-algis/iOSAutoLayoutScrollView

J'ai lu le iOS 6 changelog et l'explication sur ce sujet précis, et pense que c'est de la bonne mise en œuvre de la deuxième option (pure mise en page automatique), mais dans ce cas pourquoi l' UIScrollView se comporter de manière erratique ? Ai-je raté quelque chose ?

EDIT: C'est exactement le même problème que le #12580434 uiscrollview-mise en page automatique-problème. Les réponses ne sont que des solutions de contournement, comme quelqu'un a trouvé un bon moyen de résoudre ce problème ou est-ce un iOS bug ?

EDIT 2: j'ai trouvé une autre solution, qui permettent de garder la position de défilement dans le même état à l'utilisateur de gauche (c'est une amélioration par rapport à 12580434's accepté de répondre):

@interface GAViewController ()

@property CGPoint tempContentOffset;

@end


@implementation GAViewController

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    self.tempContentOffset = self.mainScrollView.contentOffset;
    self.scrollView.contentOffset = CGPointZero;
}

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    self.scrollView.contentOffset = self.tempContentOffset;
}

Cela veut sauver le décalage en viewWillAppear, le réinitialiser à l'origine, puis de restaurer la valeur en viewDidAppear. Le problème semble se produire entre ces deux appels, mais je ne trouve pas son origine.

22voto

Mark Kryzhanouski Points 4165

Ouais, quelque chose d'étrange s'est passé avec UIScrollView dans la pure mise en forme automatique de l'environnement. Re-lecture du SDK iOS 6.0 notes de version pour la vingtième fois que j'ai trouvé:

Notez que vous pouvez faire une sous-vue de défilement de la vue semblent flotter (pas de défilement) sur l'autre défilement de contenu en créant des contraintes entre le point de vue et une vue de l'extérieur, le défilement de l'affichage du sous-arbre, telles que le défilement de la vue superview.

Solution

Connectez votre sous-vue de l'extérieur vue. En d'autres termes, à la vue dans laquelle le scrollview est intégré.

L'IB ne nous permettent pas de définir des contraintes entre le imageView et une vue de l'extérieur, le défilement de l'affichage du sous-arbre, telles que le défilement de la vue superview puis je l'ai fait dans le code.

- (void)viewDidLoad {
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    [self.view removeConstraints:[self.view constraints]];
    [self.scrollView removeConstraints:[self.scrollView constraints]];
    [self.imageView removeConstraints:[self.imageView constraints]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_scrollView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_scrollView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_imageView(700)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_imageView(1500)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView)]];
}

Et vau! Il fonctionne!

10voto

Pion Points 251

Le montage n'a pas fonctionné pour moi. Mais cela a fonctionné:

 -(void)viewWillDisappear:(BOOL)animated
{
     [super viewWillDisappear:animated];

     self.tempContentOffset = self.scrollView.contentOffset;
     self.scrollView.contentOffset = CGPointZero;
}

- (void)viewDidLayoutSubviews {
     [super viewDidLayoutSubviews];
     self.scrollView.contentOffset = self.tempContentOffset;
}
 

0voto

Maxime Thibaut Points 26

J'ai eu un problème similaire lors de l'utilisation d'un UIScrollView dans un UIViewController avec un espace supplémentaire supérieur qui n'était pas visible dans Storyboard. La solution pour moi était de décocher la case "Ajuster les encarts de la vue de défilement" dans les propriétés du storyboard ViewController: voir la réponse Espace supplémentaire (encart) dans la vue de défilement au moment de l'exécution

-1voto

Ajoutez une propriété globale contentOffset et enregistrez le contentOffset actuel dans viewDidDisappear. Une fois que vous aurez renvoyé la méthode, la méthode viewDidLayoutSubviews sera appelée et vous pourrez définir votre contentOffset d'origine.

 - (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [self.scrollView setContentOffset:self.contentOffset animated:FALSE];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    self.contentOffset = self.scrollView.contentOffset;
    [self.scrollView setContentOffset:CGPointMake(0, 0) animated:FALSE];
}
 

-4voto

chebur Points 133

On dirait que le problème est résolu avec les dispatch_async pendant les viewWillAppear:

 - (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    CGPoint originalContentOffset = self.scrollView.contentOffset;
    self.scrollView.contentOffset = CGPointZero;

    dispatch_async(dispatch_get_main_queue(), ^{
        self.scrollView.contentOffset = originalContentOffset;
    });
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X