web-dev-qa-db-fra.com

Comment changer la position de UIPageControl dans iOS> = 8.0?

J'ai un simple UIPageViewController qui affiche le UIPageControl par défaut au bas des pages. Je me demande s’il est possible de modifier la position de UIPageControl, par exemple. être au-dessus de l'écran au lieu du bas ... J'ai regardé autour de moi et je n'ai trouvé que de vieilles discussions qui disent que je dois créer mon propre UIPageControl ... C'est ce qui est plus simple avec iOS8 et 9? Merci. 

15
Nguyen Thu

Oui, vous pouvez ajouter un contrôleur de page personnalisé pour cela. 

self.pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 50, self.view.frame.size.width, 50)]; // your position

[self.view addSubview: self.pageControl];

puis retirez 

- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController

et 

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController

Ajoutez ensuite une autre méthode déléguée:

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers
 {
     PageContentViewController *pageContentView = (PageContentViewController*) pendingViewControllers[0];
     self.pageControl.currentPage = pageContentView.pageIndex;
 }
34
Jan

Remplacez la viewDidLayoutSubviews () du pageviewcontroller et utilisez cette

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // get pageControl and scroll view from view's subviews
    let pageControl = view.subviews.filter{ $0 is UIPageControl }.first! as! UIPageControl
    let scrollView = view.subviews.filter{ $0 is UIScrollView }.first! as! UIScrollView
    // remove all constraint from view that are tied to pagecontrol
    let const = view.constraints.filter { $0.firstItem as? NSObject == pageControl || $0.secondItem as? NSObject == pageControl }
    view.removeConstraints(const)

    // customize pagecontroll
    pageControl.translatesAutoresizingMaskIntoConstraints = false
    pageControl.addConstraint(pageControl.heightAnchor.constraintEqualToConstant(35))
    pageControl.backgroundColor = view.backgroundColor

    // create constraints for pagecontrol
    let leading = pageControl.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor)
    let trailing = pageControl.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor)
    let bottom = pageControl.bottomAnchor.constraintEqualToAnchor(scrollView.topAnchor, constant:8) // add to scrollview not view

    // pagecontrol constraint to view
    view.addConstraints([leading, trailing, bottom])
    view.bounds.Origin.y -= pageControl.bounds.maxY
}
8
Cjay

Il suffit de rechercher PageControl dans la sous-classe PageViewController et de définir le cadre, l'emplacement ou tout autre paramètre

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        for subView in view.subviews {
            if  subView is  UIPageControl {
                subView.frame.Origin.y = self.view.frame.size.height - 164
            }
        }
    }
7
Trung Phan

La réponse de Shameerjan est très bonne, mais il lui faut encore une chose pour fonctionner correctement, à savoir l'implémentation d'une autre méthode de délégation:

func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {

    // If user bailed our early from the gesture, 
    // we have to revert page control to previous position
    if !completed {
         let pageContentView = previousViewControllers[0] as! PageContentViewController;
         self.pageControl.currentPage = pageContentView.pageIndex;
    }
}

En effet, si vous ne le faites pas, si vous déplacez légèrement le contrôle de page, il reviendra à la position précédente - mais le contrôle de page affichera une page différente.

J'espère que ça aide!

7
Jiri Trecak

Oui, la réponse de Shameerjan est très bonne, mais au lieu d’ajouter un autre contrôle de page, vous pouvez utiliser l’indicateur de page par défaut:

- (UIPageControl*)pageControl {
for (UIView* view in self.view.subviews) {
    if ([view isKindOfClass:[UIPageControl class]]) {
        //set new pageControl position
        view.frame = CGRectMake( 100, 200, width, height);
        return (id)view;
    }
}
return nil;
}

etendez ensuite la taille de UIPageViewController pour couvrir l’espace inférieur:

//somewhere in your code
self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height+40);
3
Max Niagolov

voici un moyen très efficace de changer la position du PageControl par défaut pour le PageViewController sans avoir à en créer un nouveau ...

extension UIPageViewController {
override open func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    for subV in self.view.subviews {
        if type(of: subV).description() == "UIPageControl" {
            let pos = CGPoint(x: subV.frame.Origin.x, y: subV.frame.Origin.y - 75 * 2)
            subV.frame = CGRect(Origin: pos, size: subV.frame.size)
        }
    }
}
}
2
Hussein Dimessi

Pour Swift:

self.pageController = UIPageControl(
                                     frame: CGRect(
                                         x: 0,
                                         y: self.view.frame.size.height - 50,
                                         width: self.view.frame.size.width,
                                         height: 50
                                     )
                                   )

self.view.addSubview(pageController)

n'oubliez pas d'utiliser pageController.numberOfPages et déléguez la pageView

puis retirez

func presentationCountForPageViewController(
    pageViewController: UIPageViewController
) -> Int

et

func presentationIndexForPageViewController(
    pageViewController: UIPageViewController
) -> Int

Ajoutez ensuite une autre méthode déléguée:

func pageViewController(
    pageViewController: UIPageViewController,
    willTransitionToViewControllers pendingViewControllers:[UIViewController]){
       if let itemController = pendingViewControllers[0] as? PageContentViewController {
           self.pageController.currentPage = itemController.pageIndex
       }
    }
}
2
Anibal Rodriguez

Version de Swift 4 de la réponse de @Jan avec bug corrigé lorsque l'utilisateur annule la transition:

Tout d'abord, vous créez un contrôle de page personnalisé:

let pageControl = UIPageControl()

Vous l'ajoutez à la vue et le positionnez comme vous le souhaitez:

self.view.addSubview(self.pageControl)
self.pageControl.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    self.pageControl.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor, constant: 43),
    self.pageControl.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -33)
])

Ensuite, vous devez initialiser la pageControl:

self.pageControl.numberOfPages = self.dataSource.controllers.count

Enfin, vous devez implémenter UIPageViewControllerDelegate et sa méthode pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:):

func pageViewController(_ pageViewController: UIPageViewController,
                        didFinishAnimating finished: Bool,
                        previousViewControllers: [UIViewController],
                        transitionCompleted completed: Bool) {
    // this will get you currently presented view controller
    guard let selectedVC = pageViewController.viewControllers?.first else { return }

    // and its index in the dataSource's controllers (I'm using force unwrap, since in my case pageViewController contains only view controllers from my dataSource)
    let selectedIndex = self.dataSource.controllers.index(of: selectedVC)!
    // and we update the current page in pageControl
    self.pageControl.currentPage = selectedIndex
}

Maintenant, en comparaison avec la réponse de @Jan, nous mettons à jour self.pageControl.currentPage en utilisant pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:) (indiqué ci-dessus), au lieu de pageViewController(_:willTransitionTo:). Cela résout le problème de la transition annulée - pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:) est toujours appelée à la fin d'une transition (elle imite également mieux le comportement du contrôle de page standard).

Enfin, pour supprimer le contrôle de page standard, veillez à supprimer l'implémentation des méthodes presentationCount(for:) et presentationIndex(for:) de UIPageViewControllerDataSource. Si les méthodes sont implémentées, le contrôle de page standard sera présenté.

Donc, vous ne voulez PAS avoir ceci dans votre code:

func presentationCount(for pageViewController: UIPageViewController) -> Int {
    return self.dataSource.controllers.count
}


func presentationIndex(for pageViewController: UIPageViewController) -> Int {
    return 0
}
2
Milan Nosáľ

Voici ma prise. Cette version modifie uniquement le code lorsque l’animation est terminée, c’est-à-dire lorsque vous accédez à la page de destination.

/** Each page you add to the UIPageViewController holds its index */
class Page: UIViewController {
    var pageIndex = 0
}

class MyPageController : UIPageViewController {

    private let pc = UIPageControl()
    private var pendingPageIndex = 0

    // ... add pc to your view, and add Pages ... 

    /** Will transition, so keep the page where it goes */
    func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController])
    {
        let controller = pendingViewControllers[0] as! Page
        pendingPageIndex = controller.pageIndex
    }

    /** Did finish the transition, so set the page where was going */
    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
    {
        if (completed) {
            pc.currentPage = pendingPageIndex
        }
    }
}
1
Ferran Maylinch

Assurez-vous que pageControl est ajouté en tant que sous-vue. Puis dans 

-(void)viewDidLayoutSubviews {
      [super viewDidLayoutSubviews];

      CGRect frame = self.pageControl.frame;
      frame.Origin.x = self.view.frame.size.width/2 - 
                       frame.size.width/2;
      frame.Origin.y = self.view.frame.size.height - 100 ;
      self.pageControl.numberOfPages = self.count;
      self.pageControl.currentPage = self.currentIndex;
      self.pageControl.frame = frame;
 }
0
Ali

C'est bien et avec plus de changement

var pendingIndex = 0;
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    if completed {
        pageControl.currentPage = pendingIndex
    }
}

func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
    let itemController = pendingViewControllers.first as! IntroPageItemViewController
    pendingIndex = itemController.itemIndex
}
0
M.R