How to make bottom panel with dots of translucent UIPageViewController?

I am doing a tutorial, and I'm trying to imitate the style of a Path tutorial like this:

http://www.appcoda.com/wp-content/uploads/2013/06/UIPageViewController-Tutorial-Screen.jpg enter image description here

My problem is if I set the delegate method as follows:

- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController { // The number of items reflected in the page indicator. return 5; } 

Then I get this dull black bar under the dots:

http://i.stack.imgur.com/pUEdh.png enter image description here

Is there a way to make this bar a translucent way, similar to setting the UINavigationBar to show through?

+42
ios iphone uipageviewcontroller
Jul 22 '13 at 4:01
source share
11 answers

It is very easy to make it work. You just need to make the pageviewcontroller higher and put the PageControl file in the XIB file. The trick first places the PageControl in the foreground (and all other common controls) at the beginning and updates the contents of the PageControl using the PageViewController. Here is the code:

 - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib. self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil]; self.pageController.dataSource = self; // We need to cover all the control by making the frame taller (+ 37) [[self.pageController view] setFrame:CGRectMake(0, 0, [[self view] bounds].size.width, [[self view] bounds].size.height + 37)]; TutorialPageViewController *initialViewController = [self viewControllerAtIndex:0]; NSArray *viewControllers = [NSArray arrayWithObject:initialViewController]; [self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil]; [self addChildViewController:self.pageController]; [[self view] addSubview:[self.pageController view]]; [self.pageController didMoveToParentViewController:self]; // Bring the common controls to the foreground (they were hidden since the frame is taller) [self.view bringSubviewToFront:self.pcDots]; [self.view bringSubviewToFront:self.btnSkip]; } - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController { NSUInteger index = [(TutorialPageViewController *)viewController index]; [self.pcDots setCurrentPage:index]; if (index == 0) { return nil; } index--; return [self viewControllerAtIndex:index]; } - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController { NSUInteger index = [(TutorialPageViewController *)viewController index]; [self.pcDots setCurrentPage:index]; index++; if (index == 3) { return nil; } return [self viewControllerAtIndex:index]; } - (TutorialPageViewController *)viewControllerAtIndex:(NSUInteger)index { TutorialPageViewController *childViewController = [[TutorialPageViewController alloc] initWithNibName:@"TutorialPageViewController" bundle:nil]; childViewController.index = index; return childViewController; } - (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController { // The number of items reflected in the page indicator. NSInteger tutorialSteps = 3; [self.pcDots setNumberOfPages:tutorialSteps]; return tutorialSteps; } - (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController { // The selected item reflected in the page indicator. return 0; } 
+46
02 Oct '13 at 15:14
source share
— -

The same effect can be achieved simply by subclassing the UIPageViewController and overriding viewDidLayoutSubviews as follows:

 -(void)viewDidLayoutSubviews { UIView* v = self.view; NSArray* subviews = v.subviews; // Confirm that the view has the exact expected structure. // If you add any custom subviews, you will want to remove this check. if( [subviews count] == 2 ) { UIScrollView* sv = nil; UIPageControl* pc = nil; for( UIView* t in subviews ) { if( [t isKindOfClass:[UIScrollView class]] ) { sv = (UIScrollView*)t; } else if( [t isKindOfClass:[UIPageControl class]] ) { pc = (UIPageControl*)t; } } if( sv != nil && pc != nil ) { // expand scroll view to fit entire view sv.frame = v.bounds; // put page control in front [v bringSubviewToFront:pc]; } } [super viewDidLayoutSubviews]; } 

Then there is no need to maintain a separate UIPageControl, etc.

+17
Jul 20 '14 at 15:26
source share

Here's the conversion of the Zerotool solution to Swift 2.1, although there may be a more elegant way to write it:

 override func viewDidLayoutSubviews() { var scrollView: UIScrollView? var pageControl: UIPageControl? // If you add any custom subviews, you will want to remove this check. if (self.view.subviews.count == 2) { for view in self.view.subviews { if (view.isKindOfClass(UIScrollView)) { scrollView = view as? UIScrollView } else if (view.isKindOfClass(UIPageControl)) { pageControl = view as? UIPageControl } } } if let scrollView = scrollView { if let pageControl = pageControl { scrollView.frame = self.view.bounds self.view.bringSubviewToFront(pageControl) } } super.viewDidLayoutSubviews() } 
+5
Feb 28 '16 at 6:30
source share

Swift 3 snippet

 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if let scrollView = view.subviews.filter({ $0 is UIScrollView }).first, let pageControl = view.subviews.filter({ $0 is UIPageControl }).first { scrollView.frame = view.bounds view.bringSubview(toFront:pageControl) } } 
+5
Oct 24 '16 at 8:26
source share

I don't think you can change the behavior of the UIPageViewController, so it seems likely that the Path application uses its own view controller. You can do the same: create your own container view controller that uses the UIPageControl to specify the current page.

+3
Jul 22 '13 at 4:47 on
source share

You can simply customize the alpha of the UIPageViewController UIPageControl.

First you should get it from the UIPageViewController as follows:

 - (UIPageControl *)getPageControlForPageViewController:(UIPageViewController *)pageViewController { for (UIView *subview in self.pageViewController.view.subviews) { if ([subview isKindOfClass:[UIPageControl class]]) { return (UIPageControl *) subview; } } return nil; } 

Then use the function. I created a property on my ViewController named childPageControl. Give UIPageViewController UIPageControl:

 self.childPageControl = [self getPageControlForPageViewController:self.pageViewController]; 

Then you can adjust the alpha to get a translucent effect:

 self.childPageControl.alpha = .5; 

You are very limited in what you can do to influence the UIPageViewController UIPageControl, but you can at least achieve this with minimal effort.

+2
May 30 '14 at 19:39
source share

A small hack that I found today.

Please see the code below.

enter image description here

 self.pageController.dataSource = self; CGRect rect = [self.view bounds]; rect.size.height+=37; [[self.pageController view] setFrame:rect]; NSArray *subviews = self.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]; } } UIView *tempview = [[UIView alloc] initWithFrame:CGRectMake(0, -30, 320, 40)]; [tempview addSubview:thisControl]; thisControl.pageIndicatorTintColor = [UIColor lightGrayColor]; thisControl.currentPageIndicatorTintColor = [UIColor greenColor]; [self.view addSubview:tempview]; 
+2
Feb 11 '16 at 19:51
source share

this code is in Swift Add the following to your UIPageViewController:

 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() for view in self.view.subviews { if view.isKindOfClass(UIScrollView) { view.frame = UIScreen.mainScreen().bounds } else if view.isKindOfClass(UIPageControl) { view.backgroundColor = UIColor.clearColor() } } } 
+1
May 09 '16 at 11:40
source share

I decide to use this code:

 - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.namesImage = @[@"page1.png", @"page2.png", @"page3.png", @"page4.png"]; self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageViewController"]; self.pageViewController.dataSource = self; TutorialContentViewController *startingViewController = [self viewControllerAtIndex:0]; NSArray *viewControllers = @[startingViewController]; [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil]; [self addChildViewController:self.pageViewController]; [self.view addSubview:self.pageViewController.view]; [self.pageViewController didMoveToParentViewController:self]; [[UIPageControl appearance] setPageIndicatorTintColor:[UIColor grayColor]]; [[UIPageControl appearance] setCurrentPageIndicatorTintColor:[UIColor whiteColor]]; [[UIPageControl appearance] setBackgroundColor: [[UIColor blackColor] colorWithAlphaComponent:0.1f]]; [[UIPageControl appearance] setOpaque:YES]; } 
+1
Nov 25 '16 at 19:53
source share

I found another desktop that suits me better.

I reuse the code specified by zerotool to get the UIPageControl (var called pageControl) and the UIScrollView (var called pageView) used by the UIPageViewController.

Once this is done in viewDidLoad, I simply deny the subtitle of the pageView clip and allow the content to spread more under the UIPageControl.

The Control page is under the page screen, so we must manually do this in front.

 - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. if( [[[self view] subviews] count] == 2 ) { UIScrollView* pageView = nil; UIPageControl* pageControl = nil; UIView* selfView = self.view; NSArray* subviews = selfView.subviews; for( NSInteger i = 0 ; i < subviews.count && ( pageView == nil || pageControl == nil ) ; i++ ) { UIView* t = subviews[i]; if( [t isKindOfClass:[UIScrollView class]] ) { pageView = (UIScrollView*)t; } else if( [t isKindOfClass:[UIPageControl class]] ) { pageControl = (UIPageControl*)t; } } if( pageView != nil && pageControl != nil ) { [pageView setClipsToBounds:NO]; [selfView bringSubviewToFront:pageControl]; } } } 

As soon as I get my pageView covering the space occupied by the pageControl, but under the control of pageControl, I just need to configure the use of the nib file for each viewController displayed as a page:

  • base view should not contain clip
  • first and only submission:
    • should be limited to set the bottom to -37 (or more if you need to, but 37 is the size of the pageControl) below the add-in
    • must pin content
0
Mar 04 '15 at 11:17
source share

I wanted to make a similar effect in the application I was working on - I used the UIPageViewController with a separate UIPageControl.

This allows you to place the UIPageControl anywhere in the view, including on top of the UIPageViewController, and maintain a constant, current page page using the UIPageViewController delegation method:

 - (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray<UIViewController *> *)previousViewControllers transitionCompleted:(BOOL)completed { if (completed) { self.pageControl.currentPage = [self.pageViewControllers indexOfObject:pageViewController.viewControllers.firstObject]; } } 

There is no need to go through the hierarchy of subframes while trying to find the internal UIPageViewController control and also not to resize the internal scroll content.

Hope this helps.

0
Oct 30 '15 at 21:01
source share



All Articles