如何在 iOS >=8.0 中更改 UIPageControl 的位置?
How to change position of UIPageControl in iOS >=8.0?
我有一个简单的 UIPageViewController,它在页面底部显示默认的 UIPageControl。我想知道是否可以修改 UIPageControl 的位置,例如位于屏幕顶部而不是底部。
我环顾四周,只发现旧的讨论说我需要创建自己的 UIPageControl。
iOS8 和 9 是不是更简单了?
谢谢。
是的,您可以为此添加自定义页面控制器。
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];
然后删除
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
和
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
然后再添加一个委托方法:
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers
{
PageContentViewController *pageContentView = (PageContentViewController*) pendingViewControllers[0];
self.pageControl.currentPage = pageContentView.pageIndex;
}
Shameerjan 的回答非常好,但它还需要一件事才能正常工作,那就是另一个委托方法的实现:
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;
}
}
这是因为如果您不这样做,只要稍微移动页面控件,它就会返回到之前的位置 - 但页面控件会显示不同的页面。
希望对您有所帮助!
对于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)
记住使用 pageController.numberOfPages 并委托 pageView
然后删除
func presentationCountForPageViewController(
pageViewController: UIPageViewController
) -> Int
和
func presentationIndexForPageViewController(
pageViewController: UIPageViewController
) -> Int
然后再添加一个委托方法:
func pageViewController(
pageViewController: UIPageViewController,
willTransitionToViewControllers pendingViewControllers:[UIViewController]){
if let itemController = pendingViewControllers[0] as? PageContentViewController {
self.pageController.currentPage = itemController.pageIndex
}
}
}
是的,Shameerjan 的回答非常好,但是您可以使用默认页面指示器而不是添加另一个页面控件:
- (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;
}
然后扩展 UIPageViewController 的大小以覆盖底部间隙:
//somewhere in your code
self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height+40);
覆盖 pageviewcontroller 的 viewDidLayoutSubviews() 并使用它
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// get pageControl and scroll view from view's subviews
let pageControl = view.subviews.filter{ [=10=] is UIPageControl }.first! as! UIPageControl
let scrollView = view.subviews.filter{ [=10=] is UIScrollView }.first! as! UIScrollView
// remove all constraint from view that are tied to pagecontrol
let const = view.constraints.filter { [=10=].firstItem as? NSObject == pageControl || [=10=].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
}
这是一种非常有效的方法来更改 PageViewController 的默认 PageControl 的位置,而无需创建新的...
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)
}
}
}
}
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
}
只需在 PageViewController 子类中查找 PageControl 并设置框架、位置或您想要的任何内容
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for subView in view.subviews {
if subView is UIPageControl {
subView.frame.origin.y = self.view.frame.size.height - 164
}
}
}
直接获取第一个view controller,在didFinishAnimating中找到index:
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
pageControl.currentPage = onboardingViewControllers.index(of: pageViewController.viewControllers!.first!)!
}
这是我的看法。此版本仅在动画结束时更改指标,即当您到达目标页面时。
/** 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
}
}
}
Swift @Jan 的回答的第 4 版 修复了用户取消转换时的错误:
首先,您创建自定义 pageControl:
let pageControl = UIPageControl()
您将它添加到视图中并根据需要定位它:
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)
])
然后你需要初始化 pageControl
:
self.pageControl.numberOfPages = self.dataSource.controllers.count
最后,你需要实现UIPageViewControllerDelegate
,它的方法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
}
现在与@Jan 的回答相比,我们使用 pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)
(如上所示)而不是 pageViewController(_:willTransitionTo:)
来更新 self.pageControl.currentPage
。这克服了取消转换的问题 - pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)
总是在转换完成时调用(它也更好地模仿了标准页面控件的行为)。
最后,要删除标准页面控件,请务必删除 UIPageViewControllerDataSource
的 presentationCount(for:)
和 presentationIndex(for:)
方法的实现 - 如果实现了这些方法,则标准页面控件将呈现。
所以,您不希望在您的代码中包含这个:
func presentationCount(for pageViewController: UIPageViewController) -> Int {
return self.dataSource.controllers.count
}
func presentationIndex(for pageViewController: UIPageViewController) -> Int {
return 0
}
确保将 pageControl 添加为子视图。
然后在
-(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;
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for view in self.view.subviews{
if view is UIScrollView{
view.frame = UIScreen.main.bounds
}
else if view is UIPageControl {
view.backgroundColor = UIColor.clear
view.frame.origin.y = self.view.frame.size.height - 75
}
}
}
Swift 5 & iOS 13.5(手动布局)
下面的示例使用自定义 UIPageControl
,布局在 UIPageViewController
的底部中心位置。要使用该代码,请将 MemberProfilePhotoViewController
替换为您用作页面的视图控制器类型。
快速笔记
- 您必须在
pageControl
上设置 numberOfPages
属性。
- 尺寸
pageControl
你可以使用 pageControl.size(forNumberOfPages: count)
.
- 确保删除
presentationCount(...)
和 presentationIndex(...)
以删除默认页面控件。
- 使用
UIPageViewControllerDelegate
的 didFinishAnimating
似乎是更新 pageControl.currentPage
. 的更好时机
代码
import Foundation
import UIKit
class MemberProfilePhotosViewController: UIPageViewController {
private let profilePhotoURLs: [URL]
private let profilePhotoViewControllers: [MemberProfilePhotoViewController]
private var pageControl: UIPageControl?
// MARK: - Initialization
init(profilePhotoURLs: [URL]) {
self.profilePhotoURLs = profilePhotoURLs
profilePhotoViewControllers = profilePhotoURLs.map { (profilePhotoURL) -> MemberProfilePhotoViewController in
MemberProfilePhotoViewController(profilePhotoURL: profilePhotoURL)
}
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
}
required init?(coder: NSCoder) {
fatalError()
}
// MARK: UIViewController
override func loadView() {
super.loadView()
pageControl = UIPageControl(frame: CGRect.zero)
pageControl!.numberOfPages = profilePhotoViewControllers.count
self.view.addSubview(pageControl!)
}
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
delegate = self
if let firstViewController = profilePhotoViewControllers.first {
setViewControllers([firstViewController],
direction: .forward,
animated: true,
completion: nil)
}
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let pageControl = pageControl {
let pageControlSize = pageControl.size(forNumberOfPages: profilePhotoViewControllers.count)
pageControl.frame = CGRect(
origin: CGPoint(x: view.frame.midX - pageControlSize.width / 2, y: view.frame.maxY - pageControlSize.height),
size: pageControlSize
)
}
}
// MARK: Private Helpers
private func indexOf(_ viewController: UIViewController) -> Int? {
return profilePhotoViewControllers.firstIndex(of: viewController as! MemberProfilePhotoViewController)
}
}
extension MemberProfilePhotosViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController,
didFinishAnimating finished: Bool,
previousViewControllers: [UIViewController],
transitionCompleted completed: Bool) {
guard let selectedViewController = pageViewController.viewControllers?.first else { return }
if let indexOfSelectViewController = indexOf(selectedViewController) {
pageControl?.currentPage = indexOfSelectViewController
}
}
}
extension MemberProfilePhotosViewController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = profilePhotoViewControllers.firstIndex(of: viewController as! MemberProfilePhotoViewController) else {
return nil
}
let previousIndex = viewControllerIndex - 1
guard previousIndex >= 0 else {
return nil
}
guard profilePhotoViewControllers.count > previousIndex else {
return nil
}
return profilePhotoViewControllers[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = profilePhotoViewControllers.firstIndex(of: viewController as! MemberProfilePhotoViewController) else {
return nil
}
let nextIndex = viewControllerIndex + 1
let profilePhotoViewControllersCount = profilePhotoViewControllers.count
guard profilePhotoViewControllersCount != nextIndex else {
return nil
}
guard profilePhotoViewControllersCount > nextIndex else {
return nil
}
return profilePhotoViewControllers[nextIndex]
}
}
我有一个简单的 UIPageViewController,它在页面底部显示默认的 UIPageControl。我想知道是否可以修改 UIPageControl 的位置,例如位于屏幕顶部而不是底部。 我环顾四周,只发现旧的讨论说我需要创建自己的 UIPageControl。 iOS8 和 9 是不是更简单了? 谢谢。
是的,您可以为此添加自定义页面控制器。
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];
然后删除
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
和
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
然后再添加一个委托方法:
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers
{
PageContentViewController *pageContentView = (PageContentViewController*) pendingViewControllers[0];
self.pageControl.currentPage = pageContentView.pageIndex;
}
Shameerjan 的回答非常好,但它还需要一件事才能正常工作,那就是另一个委托方法的实现:
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;
}
}
这是因为如果您不这样做,只要稍微移动页面控件,它就会返回到之前的位置 - 但页面控件会显示不同的页面。
希望对您有所帮助!
对于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)
记住使用 pageController.numberOfPages 并委托 pageView
然后删除
func presentationCountForPageViewController(
pageViewController: UIPageViewController
) -> Int
和
func presentationIndexForPageViewController(
pageViewController: UIPageViewController
) -> Int
然后再添加一个委托方法:
func pageViewController(
pageViewController: UIPageViewController,
willTransitionToViewControllers pendingViewControllers:[UIViewController]){
if let itemController = pendingViewControllers[0] as? PageContentViewController {
self.pageController.currentPage = itemController.pageIndex
}
}
}
是的,Shameerjan 的回答非常好,但是您可以使用默认页面指示器而不是添加另一个页面控件:
- (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;
}
然后扩展 UIPageViewController 的大小以覆盖底部间隙:
//somewhere in your code
self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height+40);
覆盖 pageviewcontroller 的 viewDidLayoutSubviews() 并使用它
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// get pageControl and scroll view from view's subviews
let pageControl = view.subviews.filter{ [=10=] is UIPageControl }.first! as! UIPageControl
let scrollView = view.subviews.filter{ [=10=] is UIScrollView }.first! as! UIScrollView
// remove all constraint from view that are tied to pagecontrol
let const = view.constraints.filter { [=10=].firstItem as? NSObject == pageControl || [=10=].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
}
这是一种非常有效的方法来更改 PageViewController 的默认 PageControl 的位置,而无需创建新的...
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)
}
}
}
}
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
}
只需在 PageViewController 子类中查找 PageControl 并设置框架、位置或您想要的任何内容
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for subView in view.subviews {
if subView is UIPageControl {
subView.frame.origin.y = self.view.frame.size.height - 164
}
}
}
直接获取第一个view controller,在didFinishAnimating中找到index:
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
pageControl.currentPage = onboardingViewControllers.index(of: pageViewController.viewControllers!.first!)!
}
这是我的看法。此版本仅在动画结束时更改指标,即当您到达目标页面时。
/** 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
}
}
}
Swift @Jan 的回答的第 4 版 修复了用户取消转换时的错误:
首先,您创建自定义 pageControl:
let pageControl = UIPageControl()
您将它添加到视图中并根据需要定位它:
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)
])
然后你需要初始化 pageControl
:
self.pageControl.numberOfPages = self.dataSource.controllers.count
最后,你需要实现UIPageViewControllerDelegate
,它的方法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
}
现在与@Jan 的回答相比,我们使用 pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)
(如上所示)而不是 pageViewController(_:willTransitionTo:)
来更新 self.pageControl.currentPage
。这克服了取消转换的问题 - pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)
总是在转换完成时调用(它也更好地模仿了标准页面控件的行为)。
最后,要删除标准页面控件,请务必删除 UIPageViewControllerDataSource
的 presentationCount(for:)
和 presentationIndex(for:)
方法的实现 - 如果实现了这些方法,则标准页面控件将呈现。
所以,您不希望在您的代码中包含这个:
func presentationCount(for pageViewController: UIPageViewController) -> Int {
return self.dataSource.controllers.count
}
func presentationIndex(for pageViewController: UIPageViewController) -> Int {
return 0
}
确保将 pageControl 添加为子视图。 然后在
-(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;
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for view in self.view.subviews{
if view is UIScrollView{
view.frame = UIScreen.main.bounds
}
else if view is UIPageControl {
view.backgroundColor = UIColor.clear
view.frame.origin.y = self.view.frame.size.height - 75
}
}
}
Swift 5 & iOS 13.5(手动布局)
下面的示例使用自定义 UIPageControl
,布局在 UIPageViewController
的底部中心位置。要使用该代码,请将 MemberProfilePhotoViewController
替换为您用作页面的视图控制器类型。
快速笔记
- 您必须在
pageControl
上设置numberOfPages
属性。 - 尺寸
pageControl
你可以使用pageControl.size(forNumberOfPages: count)
. - 确保删除
presentationCount(...)
和presentationIndex(...)
以删除默认页面控件。 - 使用
UIPageViewControllerDelegate
的didFinishAnimating
似乎是更新pageControl.currentPage
. 的更好时机
代码
import Foundation
import UIKit
class MemberProfilePhotosViewController: UIPageViewController {
private let profilePhotoURLs: [URL]
private let profilePhotoViewControllers: [MemberProfilePhotoViewController]
private var pageControl: UIPageControl?
// MARK: - Initialization
init(profilePhotoURLs: [URL]) {
self.profilePhotoURLs = profilePhotoURLs
profilePhotoViewControllers = profilePhotoURLs.map { (profilePhotoURL) -> MemberProfilePhotoViewController in
MemberProfilePhotoViewController(profilePhotoURL: profilePhotoURL)
}
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
}
required init?(coder: NSCoder) {
fatalError()
}
// MARK: UIViewController
override func loadView() {
super.loadView()
pageControl = UIPageControl(frame: CGRect.zero)
pageControl!.numberOfPages = profilePhotoViewControllers.count
self.view.addSubview(pageControl!)
}
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
delegate = self
if let firstViewController = profilePhotoViewControllers.first {
setViewControllers([firstViewController],
direction: .forward,
animated: true,
completion: nil)
}
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let pageControl = pageControl {
let pageControlSize = pageControl.size(forNumberOfPages: profilePhotoViewControllers.count)
pageControl.frame = CGRect(
origin: CGPoint(x: view.frame.midX - pageControlSize.width / 2, y: view.frame.maxY - pageControlSize.height),
size: pageControlSize
)
}
}
// MARK: Private Helpers
private func indexOf(_ viewController: UIViewController) -> Int? {
return profilePhotoViewControllers.firstIndex(of: viewController as! MemberProfilePhotoViewController)
}
}
extension MemberProfilePhotosViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController,
didFinishAnimating finished: Bool,
previousViewControllers: [UIViewController],
transitionCompleted completed: Bool) {
guard let selectedViewController = pageViewController.viewControllers?.first else { return }
if let indexOfSelectViewController = indexOf(selectedViewController) {
pageControl?.currentPage = indexOfSelectViewController
}
}
}
extension MemberProfilePhotosViewController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = profilePhotoViewControllers.firstIndex(of: viewController as! MemberProfilePhotoViewController) else {
return nil
}
let previousIndex = viewControllerIndex - 1
guard previousIndex >= 0 else {
return nil
}
guard profilePhotoViewControllers.count > previousIndex else {
return nil
}
return profilePhotoViewControllers[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = profilePhotoViewControllers.firstIndex(of: viewController as! MemberProfilePhotoViewController) else {
return nil
}
let nextIndex = viewControllerIndex + 1
let profilePhotoViewControllersCount = profilePhotoViewControllers.count
guard profilePhotoViewControllersCount != nextIndex else {
return nil
}
guard profilePhotoViewControllersCount > nextIndex else {
return nil
}
return profilePhotoViewControllers[nextIndex]
}
}