8

I'm using a UIPageViewController with Navigation set to Horizontal, Transition Style set to Scroll (in InterfaceBuilder), and no spine. Which gives me a lovely UIPageControl integrated. Now I want to be able to toggle whether it's displaying (because there's artwork underneath it).

I've tried setting presentationCountForPageViewController and presentationIndexForPageViewController to return 0 when the UIPageControl is supposed to be hidden, but those methods aren't being called when I want.

Pausing for stacktrace, I see them being called by [UIPageViewController _updatePageControlViaDataSourceIfNecessary]...I assume my app would be rejected if I tried to use that method.

Should I hunt through subviews for it, or roll my own so I have control over it, or is there some better way to toggle its visibility?

Thanks!

MattyG
  • 8,449
  • 6
  • 44
  • 48
Kaolin Fire
  • 2,521
  • 28
  • 43

8 Answers8

18

I would say, hunt through the subviews. This code successfully finds the UIPageControl in the subviews hierarchy:

NSArray *subviews = pageController.view.subviews;
UIPageControl *thisControl = nil;
for (int i=0; i<[subviews count]; i++) {
    if ([[subviews objectAtIndex:i] isKindOfClass:[UIPageControl class]]) {
        thisControl = (UIPageControl *)[subviews objectAtIndex:i];
    }
}

I'm using this to customize the color of the dots, I imagine you could do the same with the alpha value or send it to the back or something.

Apple provides no direct interface to the UIPageControl through the UIPageViewController class, but there are no illegal method calls required in order to get to it... I don't see why this would result in an app rejection.

felixthecat
  • 196
  • 2
  • 4
  • Thanks. This mirrors the answer that I posted to myself, which was apparently deleted in May.... Though in my solution, if it was a UIPageControl class, I setHidden:navhidden; and if it wasn't, I setClipsToBounds:!navhidden. Where navhidden toggled in the call.... – Kaolin Fire Aug 03 '13 at 09:03
  • 2
    It doesn't work for me, having Xcode 7.0.1, running iOS 9.0. – turingtested Oct 06 '15 at 09:06
4

You can access this for all PageControl objects by using appearance (see the UIAppearance protocol), but to get a specific instance you'd have to use recursion. Swift code:

let pageControl = UIPageControl.appearance()
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
  • 4
    For a specific instance use `UIPageControl.appearanceWhenContainedInInstancesOfClasses([MyClass.self])`. iOS 9 only if you are using swift. – Jon Jan 29 '16 at 17:41
4

Swift 3 Extension:

extension UIPageViewController {
    var pageControl: UIPageControl? {
        for view in view.subviews {
            if view is UIPageControl {
                return view as? UIPageControl
            }
        }
    return nil
    }
}
Mike Bedar
  • 632
  • 5
  • 14
3

In Swift:

    let subviews: Array = self.pageViewController.view.subviews
    var pageControl: UIPageControl! = nil

    for (var i = 0; i < subviews.count; i++) {
        if (subviews[i] is UIPageControl) {
            pageControl = subviews[i] as! UIPageControl
            break
        }
    }
King-Wizard
  • 15,628
  • 6
  • 82
  • 76
2

I implemented a category to handle this for me which gets the mess out of my code and allows me to access the pageControl via "pageController.pageControl"

Objective-C

// Header
@interface UIPageViewController (PageControl)

@property (nonatomic, readonly) UIPageControl *pageControl;

@end

I also used recursion (handled by blocks) in case Apple decides to change the implementation causing the UIPageControl to not be in the first layer of subviews.

// Implementation
#import "UIPageViewController+PageControl.h"

@implementation UIPageViewController (PageControl)

- (UIPageControl *)pageControl
{
    __block UIPageControl *pageControl = nil;
    void (^pageControlAssignBlock)(UIPageControl *) = ^void(UIPageControl *blockPageControl) {
        pageControl = blockPageControl;
    };

    [self recurseForPageControlFromSubViews:self.view.subviews withAssignBlock:pageControlAssignBlock];

    return pageControl;
}

- (void)recurseForPageControlFromSubViews:(NSArray *)subViews withAssignBlock:(void (^)(UIPageControl *))assignBlock
{
    for (UIView *subView in subViews) {
        if ([subView isKindOfClass:[UIPageControl class]]) {
            assignBlock((UIPageControl *)subView);
            break;
        } else {
            [self recurseForPageControlFromSubViews:subView.subviews withAssignBlock:assignBlock];
        }
    }
}

@end

This may be overkill for your needs but it worked well for mine

Adam Campbell
  • 646
  • 5
  • 13
2

How about a nice, up to date Swift 1-liner?

let pageControl = view.subviews.first { $0 is UIPageControl } as? UIPageControl

Or if you like an extension:

extension UIPageViewController {
    var pageControl: UIPageControl? {
        return view.subviews.first { $0 is UIPageControl } as? UIPageControl
    }
}
Andrew Tetlaw
  • 2,669
  • 22
  • 27
1

For Swift

To get the dots in the page control we can use

//dots will be an array of the dots views
let dots = pageControl.subviews

To get the current dot view

let currentDot = dots[pageControl.currentPage]

To get the other dots views

for i in 0..<dots.count {

    let dot = dots[i]

    if i == pageControl.currentPage {
        //dot => current dot



    } else {
        //dot => other dot

    }
}

After we get the dot view we can change whatever we want like

dot.layer.borderColor = .green
dot.layer.borderWidth = 1
Musa almatri
  • 5,596
  • 2
  • 34
  • 33
0

C# extension:

public static class PageViewControllerExtension{
    public static UIPageControl GetPageControl(this UIPageViewController pageViewController){
        foreach (var view in pageViewController.View.Subviews){
            var subView = view as UIPageControl;
            if (subView != null){
                return subView;
            }
        }
        return null;
    }
}
neurona.dev
  • 1,347
  • 1
  • 14
  • 12