如何在 iOS >=8.0 中更改 UIPageControl 的位置?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32822724/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 07:50:44  来源:igfitidea点击:

How to change position of UIPageControl in iOS >=8.0?

iosuipageviewcontrolleruipagecontrol

提问by Nguyen Thu

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.

我有一个简单的 UIPageViewController,它在页面底部显示默认的 UIPageControl。我想知道是否可以修改 UIPageControl 的位置,例如在屏幕顶部而不是底部。我一直在环顾四周,只发现旧的讨论说我需要创建自己的 UIPageControl。iOS8 和 9 这件事更简单吗?谢谢。

回答by Jan

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

回答by Cjay

Override the viewDidLayoutSubviews() of the pageviewcontroller and use this

覆盖 pageviewcontroller 的 viewDidLayoutSubviews() 并使用它

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // get pageControl and scroll view from view's subviews
    let pageControl = view.subviews.filter{ 
override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        for subView in view.subviews {
            if  subView is  UIPageControl {
                subView.frame.origin.y = self.view.frame.size.height - 164
            }
        }
    }
is UIPageControl }.first! as! UIPageControl let scrollView = view.subviews.filter{
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;
    }
}
is UIScrollView }.first! as! UIScrollView // remove all constraint from view that are tied to pagecontrol let const = view.constraints.filter {
let pageControl = UIPageControl()
.firstItem as? NSObject == pageControl ||
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)
])
.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 }

回答by Trung Phan

Just lookup PageControl in PageViewController subclass and set frame, location or whatever you want

只需在 PageViewController 子类中查找 PageControl 并设置框架、位置或任何你想要的

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

回答by Jiri Trecak

The Shameerjan answer is very good, but it needs one more thing to work properly, and that is implementation of another delegate method:

Shameerjan 的回答非常好,但还需要一件事才能正常工作,那就是另一个委托方法的实现:

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
}

This is because if you don't, if you move the page control just so slightly, it will go back to previous position - but the page control will show different page.

这是因为如果你不这样做,如果你稍微移动页面控件,它会回到以前的位置 - 但页面控件将显示不同的页面。

Hope it helps!

希望能帮助到你!

回答by Milan Nosá?

Swift 4 versionof @Jan's answer with fixed bugwhen the user cancels transition:

Swift 4 版本的@Jan's answer在用户取消转换时修复了错误

First, you create custom pageControl:

首先,您创建自定义 pageControl:

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


func presentationIndex(for pageViewController: UIPageViewController) -> Int {
    return 0
}

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

您将其添加到视图中并根据需要定位:

- (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;
}

Then you need to initialize the pageControl:

然后你需要初始化pageControl

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

Finally, you need to implement UIPageViewControllerDelegate, and its method pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:):

最后,您需要实现UIPageViewControllerDelegate,及其方法pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)

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)

Now in comparison with @Jan's answer, we update self.pageControl.currentPageusing 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).

现在与@Jan 的回答相比,我们self.pageControl.currentPage使用pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)(如上所示)而不是pageViewController(_:willTransitionTo:). 这克服了取消转换的问题 -pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)总是在转换完成时调用(它也更好地模仿标准页面控制的行为)。

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.

最后,要移除标准页面控件,请务必移除 的实现presentationCount(for:)presentationIndex(for:)方法UIPageViewControllerDataSource- 如果实现了方法,则将呈现标准页面控件。

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

所以,你不想在你的代码中包含这个:

func presentationCountForPageViewController(
    pageViewController: UIPageViewController
) -> Int

回答by Max Niagolov

Yes, the Shameerjan answer is very good, but instead of adding another page control you can use default page indicator:

是的,Shameerjan 的回答非常好,但您可以使用默认页面指示器,而不是添加另一个页面控件:

func presentationIndexForPageViewController(
    pageViewController: UIPageViewController
) -> Int

and then extend the size of the UIPageViewController to cover up the bottom gap:

然后扩展 UIPageViewController 的大小以覆盖底部间隙:

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

回答by Anibal R.

For swift:

对于快速:

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

remember use pageController.numberOfPages and delegate the pageView

记得使用 pageController.numberOfPages 并委托 pageView

then remove

然后删除

/** 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
        }
    }
}

and

-(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;
 }

Then add another delegate method:

然后添加另一个委托方法:

##代码##

回答by Hussein Dimessi

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 ...

这是一种非常有效的方法来更改 PageViewController 的默认 PageControl 的位置,而无需创建一个新的...

##代码##

回答by Ferran Maylinch

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

这是我的看法。此版本仅在动画完成时更改指示符,即当您到达目标页面时。

##代码##

回答by Ali

Make sure pageControl is added as subview. Then in

确保将 pageControl 添加为子视图。然后在

##代码##