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.
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;
}
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
}
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
}
}
}
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!
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);
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)
}
}
}
}
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
}
}
}
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
}
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
}
}
}
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;
}
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
}