J'ai une sous-classe UIViewController
en tant que scène dans le storyboard qui contient un UIScrollView
contenant diverses sous-vues. L'une des sous-vues est une UIButton
qui enchaîne dans une autre scène UIViewController
sous-classe. Quand je reviens de la vue (faites sortir le UIViewController
de la pile du contrôleur de navigation), je trouve que l'origine de la vue de défilement a changé, bien que les contentsize
et contentoffset
semblent correct.
Ce qui est également intéressant, c'est que l'application a une barre d'onglets, et lorsque je tabule et reviens à cette vue, la vue de défilement est correctement réglée avec un décalage à (0, 0).
Il n'y a fondamentalement aucun code impliqué dans ce processus, car il est à peu près tout dans le storyboard. Comme je suis assez nouveau dans l'utilisation du storyboard, je pense que je fais quelque chose de mal, même si je ne sais pas quoi. Des idées sur ce que cela peut être? Peut-être des problèmes ou des contraintes de dimensionnement?
En fait, je mets cette ligne de code dans viewDidDisappear
, et pour qu'elle se souvienne du décalage lorsque la vue réapparaît, j'ai ajouté cette ligne avant
self.contentOffset = self.scrollView.contentOffset;
aussi bien que
- (void)viewDidLayoutSubviews {
self.scrollView.contentOffset = self.contentOffset;
}
Dans iOS 7/8/9 simple self.automaticallyAdjustsScrollViewInsets = NO;
a résolu le problème dans mon cas.
Essayez ceci dans viewWillAppear du contrôleur de vue dans lequel vous revenez:
self.scrollView.contentOffset = CGPointMake(0, 0);
Edit: Lorsque vous ajoutez également le code de Peter, vous obtenez les meilleurs résultats avec:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
self.scrollView.contentOffset = CGPointMake(0, 0);
}
plus
- (void)viewWillDisappear:(BOOL)animated {
self.recentContentOffset = self.scrollView.contentOffset;
[super viewWillDisappear:animated];
}
et
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.scrollView.contentOffset = CGPointMake(0, self.recentContentOffset.y);
}
Vous revenez à la position de défilement d'origine, n'avez aucun effet secondaire visuel et la vue de défilement elle-même est correctement positionnée dans sa vue d'ensemble (ce qui était un problème) après son retour.
j'ai eu un problème similaire, après avoir rejeté un viewController, le contentOffset de ma tableView a été changé en (0, -64).
ma solution était un peu bizarre, j'ai essayé toutes les autres réponses mais sans succès, la seule chose qui a résolu mon problème était de changer la position tableView dans l'arborescence des contrôles du .xib
c'était le premier contrôle dans la vue parent comme ceci:
J'ai déplacé la tableView juste après l'ImageView et cela a fonctionné:
il semble que placer la vue de table dans la première position était à l'origine du problème, et déplacer la vue de table vers une autre position a résolu le problème.
P.D. Je n'utilise ni la mise en page automatique ni les storyboards
j'espère que cela peut aider quelqu'un!
J'utilise une collectionView et j'ai eu un problème similaire. Pour iOS 11: dans l'inspecteur de taille, il y a "encart de contenu". Réglez cela sur "Jamais". Cela a résolu le problème pour moi. J'espère que ça aidera quelqu'un.
Objectif c:
if (@available(iOS 11, *)) {
[UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
Rapide:
if #available(iOS 11, *) {
UIScrollView.appearance().contentInsetAdjustmentBehavior = .never
}
Dans iOS 11, j'ai rencontré un problème similaire: lorsque je reviens après avoir fait éclater un contrôleur de vue, la vue de table dans le contrôleur de vue précédent utilisé pour ajuster automatiquement son encart de contenu, ce qui a entraîné le saut brutal du contenu de la vue de dessus. La solution suivante a fonctionné pour moi dans iOS 11.
Dans Storyboard, sélectionnez la table et accédez à l'inspecteur d'attributs et décochez "Automatique" pour les champs Hauteur de la ligne et Estimation. Modifiez également les encarts de contenu de "Automatique" à "Jamais".
[]
Malheureusement, les suggestions de Peter et MacMark n'ont pas fonctionné pour moi (Xcode 5 avec mise en page automatique). La solution consistait à accéder au storyboard, à sélectionner le contrôleur de vue et à Reset to Suggested Constraints in View Controller
.
J'ai récemment posté une question sur un problème similaire, mais dans un contexte différent: le cadre ne reflète pas les contraintes de mise en page automatique après la fermeture du contrôleur de vue modale
Dans mon cas, l'origine d'une vue de conteneur personnalisée à l'intérieur de la vue de défilement est déplacée, plutôt que l'origine de la vue de défilement elle-même. En ce qui concerne la disposition automatique, la vue de conteneur personnalisée est épinglée sur les quatre côtés de la vue de défilement.
La vue du conteneur est créée et configurée par programme plutôt que dans IB. Bien que les contraintes de la vue de conteneur soient inchangées, l'origine de la vue de conteneur est déplacée après la fermeture d'un contrôleur de vue modale. Cette déconnexion entre contraintes et trames est inexplicable.
Ce qui est encore plus remarquable, c'est que le problème de déplacement d'origine est resté après que j'ai supprimé et rajouté toutes les contraintes associées.
J'ai trouvé une solution similaire: enregistrez la valeur du décalage de contenu actuel, définissez le décalage de contenu sur "zéro", laissez le système échanger vos vues, puis restaurez le décalage de contenu (c'est-à-dire une danse de décalage de contenu).
Dans mon cas, cependant, j'ai dû prendre des mesures supplémentaires pour résoudre le problème. Ma vue de défilement est une vue de défilement de pagination qui obtient ses sous-vues à partir d'une méthode tilePages (démontrée dans une ancienne vidéo WWDC). La modification du décalage de contenu de la vue de défilement déclenche la méthode tilePages via la méthode scrollViewDidScroll: de UIScrollViewDelegate. J'ai dû définir un indicateur pour désactiver tilePages pendant que je faisais la danse avec décalage de contenu, sinon l'application se bloquerait.
J'espère que je pourrai supprimer le code de la danse à contenu décalé lorsque je passerai à iOS 7.
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7) {
_isRecoredforios6 = YES;
_recordedOffsetforios6 = _scrollView.contentOffset;
_recordedSizeforios6 = _scrollView.contentSize;
_scrollView.contentOffset = CGPointZero;
}
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (_isRecoredforios6) {
_isRecoredforios6 = NO;
_scrollView.contentSize = _recordedSizeforios6;
_scrollView.contentOffset = _recordedOffsetforios6;
}
}
J'ai corrigé ce bogue ios6, peut être résolu en utilisant ces codes. J'ai résolu un bug survenu dans Scrollview. Merci avant tout mes amis!
J'ai utilisé une combinaison des différentes solutions publiées partout sur SO, et j'ai trouvé cette sous-classe:
// Keeps track of the recent content offset to be able to restore the
// scroll position when a modal viewcontroller is dismissed
class ScrollViewWithPersistentScrollPosition: UIScrollView {
// The recent content offset for restoration.
private var recentContentOffset: CGPoint = CGPoint(x: 0, y: 0)
override func willMove(toWindow newWindow: UIWindow?) {
if newWindow != nil {
// save the scroll offset.
self.recentContentOffset = self.contentOffset
}
super.willMove(toWindow: newWindow)
}
override func didMoveToWindow() {
if self.window != nil {
// restore the offset.
DispatchQueue.main.async(execute: {
// restore it
self.contentOffset = self.recentContentOffset
})
}
super.didMoveToWindow()
}
}
Testé sur iOS 11.2/Xcode 9.2.
La deuxième tentative pour ouvrir le contrôleur de vue présenté, sans avoir quitté le contrôleur de vue présenté, le problème est resté. C'est pourquoi je poste le étapes exactes qui a abouti à ma solution.
Donc, je réinitialiser les contraintes de collectionView dans le Storyboard, en veillant à ce qu'elles soient épinglées à la vue principale de ViewController.
ajouté: self.view.translatesAutoresizingMaskIntoConstraints = YES;
à l'intérieur du viewDidLoad
du contrôleur de vue de présentation.
Et stocké, en privé, le contentOffset de la vue de collection avant l'apparition du contrôleur de vue présenté de façon modale:
(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
self.contentOffset = self.collectionView.contentOffset;
self.collectionView.contentOffset = CGPointZero;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.collectionView.contentOffset = self.contentOffset;
}
récemment, j'ai rencontré ce bug, peut être résolu en utilisant ces codes:
// fix ios 6 bug begin
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7) {
isRecoredforios6 = YES;
recordedOffsetforios6 = self.tableView.contentOffset;
recordedSizeforios6 = self.tableView.contentSize;
}
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if (isRecoredforios6) {
isRecoredforios6 = NO;
self.tableView.contentSize = recordedSizeforios6;
self.tableView.contentOffset = recordedOffsetforios6;
}
}
// fix ios 6 bug end
merci Peter Jacobs!
Rien de ce qui précède n'a fonctionné pour moi, j'ai réussi à faire ma propre animation push/pull personnalisée à la place et cela fonctionne comme un charme.
Tout d'abord, ajoutez cette classe qui implémente le scénario Push
class PushAnimator: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.5
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// get reference to our fromView, toView and the container view that we should perform the transition in
let container = transitionContext.containerView
let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)!
let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!
// start the toView to the right of the screen
var frame = toView.frame
frame.Origin.x = container.frame.width
toView.frame = frame
// add the both views to our view controller
container.addSubview(toView)
container.addSubview(fromView)
// get the duration of the animation
let duration = self.transitionDuration(using: transitionContext)
// perform the animation!
UIView.animate(withDuration: duration, animations: {
var frame = fromView.frame
frame.Origin.x = -container.frame.width
fromView.frame = frame
toView.frame = container.bounds
}, completion: { _ in
// tell our transitionContext object that we've finished animating
transitionContext.completeTransition(true)
})
}
}
Ajoutez ensuite cette classe qui implémente le scénario pop
import Foundation
import UIKit
class PopAnimator: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.5
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// get reference to our fromView, toView and the container view that we should perform the transition in
let container = transitionContext.containerView
let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)!
let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!
// set up from 2D transforms that we'll use in the animation
let offScreenRight = CGAffineTransform(translationX: container.frame.width, y: 0)
// start the toView to the right of the screen
var frame = toView.frame
frame.Origin.x = -container.frame.width
toView.frame = frame
// add the both views to our view controller
container.addSubview(toView)
container.addSubview(fromView)
// get the duration of the animation
let duration = self.transitionDuration(using: transitionContext)
// perform the animation!
UIView.animate(withDuration: duration, animations: {
fromView.transform = offScreenRight
toView.frame = container.bounds
}, completion: { _ in
// tell our transitionContext object that we've finished animating
transitionContext.completeTransition(true)
})
}
}
Ajoutez ensuite cette ligne à votre méthode viewDidLoad pour modifier le délégué par défaut NavigationController
self.navigationController?.delegate = self
Et voyez la magie :)
Juste au cas où rien de ce qui précède n'a aidé, j'ai eu ce problème ainsi que le problème pour moi était que j'avais le code suivant ..
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableView.reloadData()
}
Commentant cette ligne reloadData () a résolu le problème pour moi. Je n'avais pas besoin de cette ligne, donc je ne sais pas pourquoi je l'ai même ajoutée!
Espérons que cette solution aide quelqu'un d'autre.
Après avoir essayé beaucoup de choses:
J'ai réalisé que le problème concernait la valeur estimatedRowHeight
, qui était définie sur 50 pixels, alors qu'elle devrait être ~ 150 pixels. La mise à jour de la valeur a résolu le problème et maintenant la vue de table conserve le même décalage.