web-dev-qa-db-fra.com

Comment rendre la barre inférieure avec des points d'un UIPageViewController translucide?

Je suis en train de faire un tutoriel, et j'essaie d'émuler le style du tutoriel de Path comme ceci:

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

Mon problème est que si vous définissez la méthode déléguée comme suit:

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

Ensuite, je reçois cette stupide barre noire sous les points:

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

Existe-t-il un moyen de rendre cette barre translucide d'une manière similaire à la définition d'un UINavigationBar sur translucide?

43
Mike V

Il est très facile de le faire fonctionner. Vous n'avez qu'à augmenter la taille du visualiseur de page et à placer un PageControl dans le fichier XIB. L'astuce consiste à placer le PageControl au premier plan (et tous les autres contrôles courants) au début, et à mettre à jour le contenu du PageControl avec le PageViewController. Voici le 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
Alex R. R.

Le même effet peut être obtenu simplement en sous-classant UIPageViewController et en remplaçant viewDidLayoutSubviews comme suit:

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

Ensuite, il n'est pas nécessaire de maintenir un UIPageControl séparé et autres.

18
zeroimpl

Extrait Swift 3

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

Voici une conversion de la solution de Zerotool en Swift 2.1, bien qu'il existe probablement une façon plus élégante de l'écrire:

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
markedwardmurray

Je ne pense pas que vous puissiez changer le comportement de UIPageViewController, il semble donc probable que l'application Path utilise son propre contrôleur de vue. Vous pouvez faire de même: créez votre propre contrôleur de vue de conteneur qui utilise un UIPageControl pour indiquer la page en cours.

3
Caleb

Petit hack que j'ai trouvé aujourd'hui ..

Veuillez consulter le code ci-dessous.

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
mandeep-dhiman

Vous pouvez simplement ajuster l'alpha de l'UIPageViewController UIPageControl.

Tout d'abord, vous devez le récupérer à partir d'UIPageViewController comme ceci:

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

      return nil;
    }

Ensuite, utilisez la fonction. J'ai créé une propriété sur mon ViewController appelée childPageControl. Donnez-lui le UIPageViewController UIPageControl:

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

Ensuite, vous pouvez ajuster l'alpha pour donner un effet translucide:

self.childPageControl.alpha = .5;

Vous êtes très limité dans ce que vous pouvez faire pour affecter l'UIPageControl de l'UIPageViewController, mais vous pouvez au moins y parvenir avec peu d'effort.

2
Carter Hudson

Je résous en utilisant ce 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
MMSousa

Je voulais faire un effet similaire dans l'application sur laquelle je travaillais - j'ai utilisé un UIPageViewController avec un UIPageControl séparé.

Cela vous permet de placer l'UIPageControl où vous le souhaitez dans la vue, y compris au-dessus de l'UIPageViewController, et de maintenir à jour son point de page actif via la méthode déléguée UIPageViewController:

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

Pas besoin de parcourir la hiérarchie de la sous-vue pour essayer de trouver le contrôle de page UIPageViewController interne, ni de redimensionner le contenu de la vue de défilement interne.

J'espère que cela t'aides.

1
crafterm

ce code est en Swift Ajoutez le suivant dans votre 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
Mohsin Qureshi

J'ai trouvé une autre solution de contournement qui me convient mieux.

Je réutilise le code donné par zerotool pour obtenir le UIPageControl (var appelé pageControl) et le UIScrollView (var appelé pageView) utilisé par le UIPageViewController.

Une fois cela fait dans le viewDidLoad, j'empêche simplement la sous-vue de clip de pageView et laisse le contenu se propager davantage sous UIPageControl.

Le pageControl est sous la pageView, nous devons donc le faire venir manuellement devant.

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

Une fois que je reçois ma pageView couvrant l'espace occupé par la pageControl mais sous la pageControl, je dois juste ajuster l'utilisation du fichier nib pour chaque viewController affiché comme page:

  • la vue de base ne doit pas être coupée
  • la première et seule sous-vue:
    • devrait avoir une contrainte pour définir le bas à -37 (ou plus si vous en avez besoin mais 37 est la taille de la pageControl) du bas de la vue d'ensemble
    • devrait couper le contenu
0
MessuKilkain