47

i'm using UIPageViewController in my app and it's working fine. however, it's page control which has been added automatically has a black background which is hiding the current view controller's bottom material (See picture below). is it possible to call the UIPageViewController's page control and change it's color? i want the page control to be shown over the view controller (example, the Path app's walkthrough) like setting the color instead of black to clear.

enter image description here

user1938695
  • 623
  • 1
  • 5
  • 14
  • These may be helpful. http://stackoverflow.com/questions/17684922/changing-uipageviewcontroller-own-pagecontroller-regarding-color-of-dots http://stackoverflow.com/questions/17466718/can-we-customize-the-page-indicator-in-uipageviewcontroller – Stu P. Aug 23 '13 at 17:20

9 Answers9

92

You can use appearance to change the color of UIPageControl as otherwise it is not accessible. Try doing it in your AppDelegate's didFinishLaunchingWithOptions function as given below.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UIPageControl *pageControl = [UIPageControl appearance];
    pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
    pageControl.currentPageIndicatorTintColor = [UIColor blackColor];
    pageControl.backgroundColor = [UIColor blueColor];

    return YES;
}

To apply style only to a particular view controller, you can use appearanceWhenContainedIn instead as following:

UIPageControl *pageControl = [UIPageControl appearanceWhenContainedIn:[MyViewController class], nil];

Only UIPageControl objects contained in the MyViewController are going to get this style.

EDIT: The black background around UIPageControl at the bottom of your screen is due to the background color of your UIPageViewController not UIPageControl. You can change this color as following:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blueColor]; //Set it to whatever you like
}
Yas Tabasam
  • 10,517
  • 9
  • 48
  • 53
  • 2
    thank you but it actually couldn't make it transparent so that i can show what's under it ([uicolor clearcolor]). however, it's a valuable piece of information. i got a question and hope you give me more info on. how does it know which pageControl i'm targeting ? how does the appearance work? Thank you so much! – user1938695 Aug 23 '13 at 18:23
  • @user1938695 If you want it to be transparent, take the last line of his code and change it to read: `pageControl.backgroundColor = [[UIColor blueColor] colorWithAlphaComponent:0.5f];` – BrianS Jan 24 '14 at 05:55
  • This gets me close but I'm still unable to get the background to be transparent. – Pork 'n' Bunny Feb 10 '14 at 04:24
  • @Pork'n'Bunny - is `pageControl.backgroundColor = [UIColor clearColor];` not working for you? – Yas Tabasam Feb 10 '14 at 06:02
  • @Pork'n'Bunny - are you using `UIPageViewController`? – Yas Tabasam Feb 11 '14 at 06:08
  • Yeah, it's UIPageViewController. It looks the same as the screenshot in the OP question even after setting the backgroundColor of the pageControl to clearColor or even a different color and changing the alpha. Its certainly not what I expect... Your code definitely changes the attributes of the relevant elements. So I can change the color fine, but clearColor results in black. – Pork 'n' Bunny Feb 12 '14 at 18:57
  • 3
    This is happening due to your `UIPageControllerView` view having no color which essentially shows as black. Add this to your `UIPageViewController`'s `viewDidLoad:` function to change black color to red. `self.view.backgroundColor = [UIColor redColor];` – Yas Tabasam Feb 13 '14 at 21:50
  • Hmmm ... the thing with this setting of backgroundColor is that apparently the size of the page control is always the original size, it doesn't change when more page bullets are added - which leads to a strange result. – TheEye Mar 14 '14 at 09:53
28

Updated for Swift 3:

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

Swift 2 example for anyone that needs it. Put this inside your UIPageController subclass.

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    for view in self.view.subviews {
        if view is UIScrollView {
            view.frame = UIScreen.mainScreen().bounds
        } else if view is UIPageControl {
            view.backgroundColor = UIColor.clearColor()
        }
    }
}
Adam Nelson
  • 7,932
  • 11
  • 44
  • 64
jlichti
  • 867
  • 9
  • 7
  • Hi @Imran - the objC code from orkenstein above is essentially the same. I was just providing a swift example here for others. – jlichti Feb 09 '16 at 09:11
  • What part is not working? I can't help unless you explain your problem a bit better. You could also just port this code to ObjC pretty easily too. – jlichti Feb 09 '16 at 13:45
  • 1
    For me it works. I just changed view.frame = UIScreen.mainScreen().bounds into view.frame = self.view.bounds – Jan Doornbos May 27 '16 at 09:55
  • For me this swift version works but it also sets the page controller indicators to clear as well... is there a way I can show the indicators? or change their colours? – Agustin Jun 28 '16 at 01:06
  • It worked for me on Swift 3.0 / XCode 8.3. iOS 10.3.1. I had to add this method in the "UIPageViewController". Added it in a hurry by mistake in my ContentViewController. – Darkwonder May 16 '17 at 07:34
  • This is perfect. Thanks for the easy solution and non-hacky way of doing it. – Scott D May 18 '17 at 18:40
11

Add the following code in the UIPageViewController.

- (void)viewDidLoad {
    [super viewDidLoad];
    [[UIPageControl appearance] setPageIndicatorTintColor: [UIColor grayColor]];
    [[UIPageControl appearance] setCurrentPageIndicatorTintColor: [UIColor whiteColor]];
    [[UIPageControl appearance] setBackgroundColor: [UIColor darkGrayColor]];
}
Brandon Yang
  • 2,380
  • 1
  • 15
  • 6
9

Just subclass UIPageViewController and add this code:

- (void)viewDidLayoutSubviews {
  [super viewDidLayoutSubviews];
  for (UIView *view in self.view.subviews) {
    if ([view isKindOfClass:[NSClassFromString(@"_UIQueuingScrollView") class]]) {
      CGRect frame = view.frame;
      frame.size.height = view.superview.frame.size.height;
      view.frame = frame;
    }
  }
}

This will extend internal scroll view frame.

orkenstein
  • 2,810
  • 3
  • 24
  • 45
5

Here is the Swift 2+ version of Yas-T's Answer

//In AppDelegate
let pageControl = UIPageControl.appearance()
pageControl.pageIndicatorTintColor = UIColor.lightGrayColor()
pageControl.currentPageIndicatorTintColor = UIColor.blackColor()
pageControl.backgroundColor = UIColor.blueColor()

//Or in your ViewController (Only available on IOS 9.0)
if #available(iOS 9.0, *) {
   let pageControl = UIPageControl.appearanceWhenContainedInInstancesOfClasses([ViewController.self])
   pageControl.pageIndicatorTintColor = UIColor.lightGrayColor()
   pageControl.currentPageIndicatorTintColor = UIColor.darkGrayColor()
}
Community
  • 1
  • 1
Rafat touqir Rafsun
  • 2,777
  • 28
  • 24
3

Here is the Swift 3+ version of accepted Answer (with a plus of a custom Color created):

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    if #available(iOS 9.0, *) {

        let pageControl = UIPageControl.appearance(whenContainedInInstancesOf: [UIPageViewController.self])
        pageControl.pageIndicatorTintColor = UIColor.init(colorLiteralRed: 43/255.0, green: 170/255.0, blue: 226/255.0, alpha: 0.4)
        pageControl.currentPageIndicatorTintColor = UIColor.init(colorLiteralRed: 43/255.0, green: 170/255.0, blue: 226/255.0, alpha: 1.0)        
    }

    return true
}
Alex
  • 271
  • 2
  • 4
  • 18
3

Override the function viewDidLayoutSubviews() in PageViewController:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    for view in view.subviews{
        if view is UIScrollView{
            view.frame = UIScreen.main.bounds
        }else if view is UIPageControl{
            view.backgroundColor = UIColor.clear
        }
    }
}
Noel Widmer
  • 4,444
  • 9
  • 45
  • 69
AnhSang
  • 150
  • 4
0

Well, I found a working solution. Inside your UIPageViewController, just add this code:

-(void)viewDidLayoutSubviews
{
   [super viewDidLayoutSubviews];

   for (UIView *view in self.view.subviews)
   {
       if ([view isKindOfClass:UIScrollView.class])
       {
           CGRect frame      = view.frame;

           frame.size.height = view.superview.frame.size.height;

           view.frame        = frame;
       }

       if ([view isKindOfClass:UIPageControl.class])
       {
           CGFloat newHeight    = 22;

           CGRect frame         = view.frame;

           frame.origin.y      += frame.size.height - newHeight;
           frame.size.height    = newHeight;

           view.frame           = frame;
           view.backgroundColor = UIColor.darkGrayColor;
           view.alpha           = 0.3;
       }
   }

}

ALiEN
  • 1
  • 1
  • 2
0

See my setup method's code in which I change page view controller's page control color and it's worked for me.

private func setupPageController() {

    self.pageController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
    self.pageController?.dataSource = self
    self.pageController?.delegate = self
    self.pageController?.view.backgroundColor = .clear
    self.pageController?.view.frame = CGRect(x: 0,y: 0,width: self.view.frame.width,height: self.view.frame.height)
    self.addChild(self.pageController!)
    self.view.addSubview(self.pageController!.view)

    for item in self.pageController?.view?.subviews ?? []{
        if item is UIPageControl{
            (item as! UIPageControl).pageIndicatorTintColor = #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)
            (item as! UIPageControl).currentPageIndicatorTintColor = #colorLiteral(red: 1, green: 0.7489039302, blue: 0, alpha: 1)
            break
        }
    }
    let initialVC = strBoard.instantiateViewController(withIdentifier: "TutorialOneVC")

    self.pageController?.setViewControllers([initialVC], direction: .forward, animated: true, completion: nil)

    self.pageController?.didMove(toParent: self)
}
matthias_h
  • 11,356
  • 9
  • 22
  • 40
Krishan kumar
  • 36
  • 1
  • 5