web-dev-qa-db-fra.com

Contenu enfoncé dans un UIPageViewController avec UINavigationController

MISE À JOUR 2

J'ai exécuté et testé mon application dans le simulateur iOS à l'aide d'un périphérique de 4 pouces. Si j'utilise un périphérique 3,5 pouces, l'étiquette ne saute pas. Dans mon fichier .xib, sous Méthodes simulées, je l’ai défini comme Retina 4 pouces plein écran. Une idée de pourquoi je ne vois ce problème que sur un appareil de 4 pouces?

MISE À JOUR 1

Dans IB, si je choisis "Barre de navigation" dans Métriques simulées, mon étiquette saute toujours. Le seul moyen d'obtenir un rendu correct de l'étiquette sur le premier écran est de ne pas définir de contrôleur de navigation comme contrôleur de vue racine de ma fenêtre.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

RootViewController de ma fenêtre est défini sur un UINavigationController dont rootViewController est doté d'un UIPageViewController.

Lorsque mon application est chargée, la vue initiale est présentée avec son contenu légèrement abaissé, à peu près de la même taille qu'une barre de navigation. Lorsque je fais défiler le pageViewController, le contenu saute à l'endroit où il a été placé dans le nib, et tous les autres viewControllers chargés par le pageViewController conviennent.

uipageviewcontroller with navigationcontroller

Dans mon appDélégant:

self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[ContainerViewController new]];

Dans ContainerViewController:

- (void)viewDidLoad {

    [super viewDidLoad];

    self.pvc = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll
                                               navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
                                                             options:nil];
    self.pvc.dataSource = self;
    self.pvc.delegate = self;
    DetailViewController *detail = [DetailViewController new];
    [self.pvc setViewControllers:@[detail]
                       direction:UIPageViewControllerNavigationDirectionForward
                        animated:false
                      completion:nil];

    [self addChildViewController:self.pvc];
    [self.view addSubview:self.pvc.view];
    [self.pvc didMoveToParentViewController:self];
}
59
djibouti33

J'ajoute donc une autre réponse après un développement ultérieur et je pense enfin avoir compris ce qui se passait. On dirait que dans iOS7, UIPageViewController a son propre UIScrollView. Pour cette raison, vous devez définir automaticallyAdjustsScrollViewInsets sur false. Voici ma viewDidLoad maintenant:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.automaticallyAdjustsScrollViewInsets = false;

    DetailViewController *detail = [[DetailViewController alloc] init];
    [self setViewControllers:@[detail]
                   direction:UIPageViewControllerNavigationDirectionForward
                    animated:false
                  completion:nil];
}

Pas besoin de mettre quoi que ce soit dans viewWillLayoutSubviews (comme l’a suggéré une de mes réponses précédentes).

83
djibouti33

Ceci est certainement causé par automaticallyAdjustsScrollViewInsets, comme d’autres affiches (y compris @ djibouti33). Cependant, cette propriété est étrange de deux manières:

  1. Il doit être défini sur UINavigationController. Si vous le définissez sur un contrôleur enfant géré par une UINavigationController, cela n'aura aucun effet. 1
  2. Cela ne s'applique que lorsqu'une vue de défilement est à l'indice zéro dans les sous-vues d'un contrôleur. 2

Ces deux mises en garde devraient expliquer les problèmes intermittents rencontrés par d’autres personnes du fil.

TLDR: Une solution de contournement que j'ai choisie consiste à ajouter une vue factice à la variable UIPageViewController d'indice zéro afin d'éviter que le paramètre ne s'applique à scrollView dans le contrôleur de page, comme suit:

pageViewController.view.insertSubview(UIView(), atIndex: 0) // Swift

[pageViewController.view insertSubview: [UIView new] atIndex: 0]; // obj-c

Il serait préférable de définir vous-même la contentInset sur la vue de défilement, mais malheureusement, la UIPageViewController n'expose pas la vue de défilement.

22
John Gibb

Décochez simplement Under Top Bars pour les deux: UIPageViewController et votre PageContentViewController personnalisé:

 enter image description here

11

Ma réponse initiale résolut le problème pour le moment, mais après un moment, le même problème revint me mordre.

Utilisation de la hiérarchie viewController suivante:

-- UINavigationController
  -- MyPageViewController
    -- MyDetailViewController

Voici ce que j'ai fait pour le résoudre:

Dans MyPageViewController.m

@interface MyPageViewController () <delegates>
  @property (strong) MyDetailViewController *initialViewController;
@end

- (void)viewDidLoad
{
    ...

    // set this once, because we're going to use it in viewWillLayoutSubviews,
    // which gets called multiple times
    self.initialViewController = [MyDetailViewController new];
}

// the problem seemed to stem from the fact that a pageViewController couldn't
// properly lay out it's child view controller initially if it contained a 
// scroll view. by the time we're in layoutSubviews, pageViewController seems to
// have gotten it's bearings and everything is laid out just fine.
- (void)viewWillLayoutSubviews
{
    [self setViewControllers:@[self.initialViewController]
                   direction:UIPageViewControllerNavigationDirectionForward
                    animated:false
                  completion:nil];
}
4
djibouti33

Essayez de décocher ces 2 options sur votre storyboard

 enter image description here

3
apinho

J'ai le même problème. Je le résous en mettant setViewControllers pour la première page dans viewDidLoad de UIPageViewController au lieu de le définir lorsque je crée une instance de UIPageViewController. En outre, je dois définir automatiquementAdjustsScrollViewInsets sur NO.

3
howa

J'ai eu un problème similaire, mais aucune des solutions ici n'a fonctionné. Mon problème était que chaque fois que je passais à la page suivante, le contenu sautait vers le bas, se terminant à la bonne position, mais commençant à 20 pixels de trop, ce qui est clairement lié à la barre d'état. Mon conteneur VC n'était pas un VC de navigation. Après m'être tiré les cheveux pendant un moment, la solution qui a finalement fonctionné pour moi consistait simplement à m'assurer qu'aucune des contraintes de mon contenu VC n'était connectée au guide de présentation supérieur. Cela peut ou peut ne pas être réalisable dans votre cas, mais dans le mien c'était, et c'était la seule chose qui a résolu le saut de contenu. Aussi très curieusement, ce problème ne s'est manifesté que lorsque le style de transition a été défini pour défiler. Le simple fait de changer de page en boucle a fait disparaître le problème. Mais j'avais besoin de faire défiler. J'espère que ceci aide quelqu'un d'autre.

3
Danny

Essayez de sélectionner UIPageViewController dans le storyboard et décochez les cases "Sous les barres inférieures" et "Sous les barres opaques" dans l'Inspecteur des attributs.

1
acid beast

Aucun de ceux ci-dessus n'a fonctionné pour moi 

Ici j'ai trouvé la solution

var pageMenu : CAPSPageMenu?

Au lieu d'ajouter comme ça

self.view.addSubview(pageMenu!.view)

Ajoutez votre CAPSPageMenu comme ci-dessous

addChildViewController(pageMenu!) 
self.view.addSubview(pageMenu!.view) 
pageMenu!.didMove(toParentViewController: self)

Référence: iOS Swift: SlidingMenuView Position incorrecte après avoir présenté imagePicker

Bon codage!

0
Sanju

Comme indiqué par "Bo:": Putting self.edgesForExtendedLayout = UIRectEdgeNone; dans le viewDidLoad de MyPageViewController a résolu le problème. - Bo

0
osxdirk

Je vois le même problème que décrit par @Danny sur iOS 9. J'ai essayé de mettre à jour toutes mes contraintes pour qu'elles ne soient pas contraintes aux marges , mais cela n'a pas résolu le problème. J'ai fini par adopter un hack similaire à this comme suit;

  • Pour chaque page de contenu à afficher dans UIPageViewController, recherchez la contrainte la plus haute, celle située entre le haut d'une vue et le bas du guide de présentation supérieur, et ajoutez-y une sortie au contrôleur de vue.
  • Dans chaque contrôleur de vue doté d'une telle prise, ajoutez une autre propriété pour la distance maximale préférée. Les deux sorties ressemblent à ceci (en Swift):

    @IBOutlet weak var topGuideConstraint: NSLayoutConstraint!
    var topDistance: CGFloat!
    
  • Dans viewDidLoad(), définissez topDistance sur la valeur attribuée à la contrainte dans le storyboard:

    override func viewDidLoad() {
        super.viewDidLoad()
        topDistance = topGuideConstraint.constant
    }
    
  • Dans viewWillLayoutSubviews(), assurez-vous que la contrainte a la valeur appropriée, en ajustant la hauteur de la barre d'état lorsque le topLayoutGuide.length est égal à zéro, ce qui semble être le cas lors de la transition , mais pas une fois terminée: 

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        topGuideConstraint.constant = topDistance + (
            topLayoutGuide.length == 0
                ? UIApplication.sharedApplication().statusBarFrame.size.height
                : 0
        )
    }
    

Répétez cette opération pour chaque contrôleur d'affichage de contenu affiché dans UIPageViewController. Ajustez le décalage comme il convient si vous affichez également une barre UINavigation.

C'est un bidon malheureux, et je déteste devoir le faire, mais après de nombreuses heures à essayer différentes choses, je suis au moins heureux d'avoir quelque chose qui fonctionne pour que je puisse passer à autre chose.

0
theory

La version de Swift de la réponse de djibouti33 (à l'exclusion de la ligne qui ne fait pas partie de la résolution du problème)

Swift 3.0

override func viewDidLoad() {
    super.viewDidLoad()
    self.automaticallyAdjustsScrollViewInsets = false
}
0
Kqtr

c'est la première fois que j'écris sur le débordement de pile, mais je cherche une solution à ce problème depuis plus d'une semaine maintenant. 

Voici une solution que j'ai proposée, j'espère que cela fonctionnera pour tous ceux qui ont le même problème.

Je ne sais pas comment vous initialisez votre cadre pour votre contrôleur de vue de détail, mais je vais supposer que vous pourriez utiliser: self.view.frame.size.height;

essayez d’utiliser: self.view.frame.size.height - = self.navigationController.navigationBar.bounds.size.height;

J'espère que cela t'aides

0
CalebDavis

Comme @ djibouti33 déjà posté: 

un pageViewController ne pouvait pas disposer correctement son contrôleur de vue enfant au début s'il contenait un voir défiler. au moment où nous sommes dans layoutSubviews, pageViewController semble avoir pris ses marques et tout est très bien présenté

Attendre le chargement de layoutSubViews avant de définir des viewControllers sur UIPageViewController était la seule chose qui fonctionnait pour moi.

override func viewDidLoad() {
    super.viewDidLoad()
    self.pageViewController = self.storyboard?.instantiateViewController(withIdentifier: "yourPageViewController") as? UIPageViewController       
    self.pageViewController?.dataSource = self

    pageViewController?.automaticallyAdjustsScrollViewInsets = false    
    self.pageViewController?.view.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.height)       
    self.addChildViewController(self.pageViewController!)        
    self.view.addSubview((self.pageViewController?.view)!)       
    self.pageViewController?.didMove(toParentViewController: self)
}


override func viewDidLayoutSubviews() {
    let startVC = self.viewControllerAtIndex(index: 0) as infoDataViewController     
    let viewControllers = NSArray(object: startVC)    
    self.pageViewController?.setViewControllers(viewControllers as? [UIViewController], direction: .forward, animated: true, completion: nil)
}
0
QitVision

Au début, ma hiérarchie de contrôleur de vue ressemblait à ceci:

-- UINavigationController
  -- MyContainerViewController
    -- UIPageViewController
      -- MyDetailViewController

Je l'ai configuré de cette manière pour que MyContainerViewController puisse gérer une barre d'outils. J'ai limité mon problème à MyContainerViewController, puis je me suis dit que je n'en ai même pas besoin si je sous-classe UIPageViewController. Maintenant, ma hiérarchie ressemble à ceci:

-- UINavigationController
  -- MyPageViewController
    -- MyDetailViewController

MyPageViewController gère sa toolbar et tout fonctionne comme prévu, aussi bien sur un périphérique 4 pouces que sur un périphérique 3,5 pouces.

0
djibouti33