How to change position of UIPageControl in iOS >=8

2020-05-19 10:37发布

I have a simple UIPageViewController which displays the default UIPageControl at the bottom of the pages. I wonder if it's possible to modify the position of the UIPageControl, e.g. to be on top of the screen instead of the bottom. I've been looking around and only found old discussions that say I need to create my own UIPageControl. Is this thing simpler with iOS8 and 9? Thanks.

12条回答
我欲成王,谁敢阻挡
2楼-- · 2020-05-19 11:16

Just get the first view controller and find out the index in didFinishAnimating:

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

    pageControl.currentPage = onboardingViewControllers.index(of: pageViewController.viewControllers!.first!)!
}
查看更多
聊天终结者
3楼-- · 2020-05-19 11:19

Swift 4 version of @Jan's answer with fixed bug when the user cancels transition:

First, you create custom pageControl:

let pageControl = UIPageControl()

You add it to the view and position it as you want:

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)
])

Then you need to initialize the pageControl:

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

Finally, you need to implement UIPageViewControllerDelegate, and its method 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
}

Now in comparison with @Jan's answer, we update self.pageControl.currentPage using pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:) (shown above), instead of pageViewController(_:willTransitionTo:). This overcomes the problem of cancelled transition - pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:) is called always when a transition was completed (it also better mimics the behavior of standard page control).

Finally, to remove the standard page control, be sure to remove implementation of presentationCount(for:) and presentationIndex(for:) methods of the UIPageViewControllerDataSource - if the methods are implemented, the standard page control will be presented.

So, you do NOT want to have this in your code:

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


func presentationIndex(for pageViewController: UIPageViewController) -> Int {
    return 0
}
查看更多
smile是对你的礼貌
4楼-- · 2020-05-19 11:19

Here's my take. This version only changes de indicator when the animation is finished, i.e. when you get to the destination page.

/** 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
        }
    }
}
查看更多
Melony?
5楼-- · 2020-05-19 11:23

here s a very effective way to change the position of the default PageControl for the PageViewController without having the need to create a new one ...

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)
        }
    }
}
}
查看更多
三岁会撩人
6楼-- · 2020-05-19 11:27

Yes, you can add custom page controller for that.

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];

then remove

- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController

and

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController

Then add another delegate method:

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers
 {
     PageContentViewController *pageContentView = (PageContentViewController*) pendingViewControllers[0];
     self.pageControl.currentPage = pageContentView.pageIndex;
 }
查看更多
\"骚年 ilove
7楼-- · 2020-05-19 11:27

For 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)

remember use pageController.numberOfPages and delegate the pageView

then remove

func presentationCountForPageViewController(
    pageViewController: UIPageViewController
) -> Int

and

func presentationIndexForPageViewController(
    pageViewController: UIPageViewController
) -> Int

Then add another delegate method:

func pageViewController(
    pageViewController: UIPageViewController,
    willTransitionToViewControllers pendingViewControllers:[UIViewController]){
       if let itemController = pendingViewControllers[0] as? PageContentViewController {
           self.pageController.currentPage = itemController.pageIndex
       }
    }
}
查看更多
登录 后发表回答