web-dev-qa-db-fra.com

Changer la page de UIPageViewController par programme ne met pas à jour le UIPageControl

Dans ma classe UIPageViewController personnalisée:

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.model = [[BSTCMWelcomingPageViewModel alloc] init];
        self.dataSource = self.model;
        self.delegate = self;

        self.pageControl = [UIPageControl appearance];
        self.pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
        self.pageControl.currentPageIndicatorTintColor = [UIColor blackColor];
    }
    return self;
}

Ensuite, je configure par programmation la ViewController courante lorsqu'un bouton est enfoncé:

- (void)scrollToNext
{
    UIViewController *current = self.viewControllers[0];
    NSInteger currentIndex = [self.model indexForViewController:current];
    UIViewController *nextController = [self.model viewControllerForIndex:++currentIndex];
    if (nextController) {
        NSArray *viewControllers = @[nextController];
        // This changes the View Controller, but PageControl doesn't update
        [self setViewControllers:viewControllers
                       direction:UIPageViewControllerNavigationDirectionForward
                        animated:YES
                      completion:nil];
        //Nothing happens!
        [self.pageControl setCurrentPage:currentIndex];

        //Error: _installAppearanceSwizzlesForSetter: Not a setter!
        [self.pageControl updateCurrentPageDisplay];
    }
}

Si je ne peux pas faire cela avec la UIPageControl qui "appartient" à ma UIPageViewController, je vais simplement essayer de créer le mien. Mais ce serait bien si cela était possible tho!

16
Johannes

pour mettre à jour votre indicateur UIPageControl, vous devez implémenter une méthode de source de données de UIPageViewController (la méthode UIPageViewControllerDataSource):

-(NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController

Cette méthode est responsable de la mise à jour de l'indicateur de contrôle de page (lorsque vous utilisez UIPageViewController). Il vous suffit de renvoyer la valeur de la page en cours dans cette méthode. La méthode est appelée par défaut lorsque vous utilisez/appelez setViewControllers sur votre UIPageViewController personnalisé.

Ainsi, le morceau de code que vous devez écrire est le suivant:

- (void)scrollToNext
{
    UIViewController *current = self.viewControllers[0];
    NSInteger currentIndex = [self.model indexForViewController:current];
    UIViewController *nextController = [self.model viewControllerForIndex:++currentIndex];
    if (nextController) {
        NSArray *viewControllers = @[nextController];
       // This changes the View Controller and calls the presentationIndexForPageViewController datasource method
       [self setViewControllers:viewControllers
                   direction:UIPageViewControllerNavigationDirectionForward
                    animated:YES
                  completion:nil];
}

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
    return currentIndex;
}

J'espère que ceci résoudra votre problème. :)

27
anshul

Comme mentionné dans la réponse acceptée, vous devez implémenter 

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController

Mais pour moi, il suffisait de l'utiliser comme ceci:

Objectif c:

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
    // The selected item reflected in the page indicator.
    return [self.controllers indexOfObject:[pageViewController.viewControllers firstObject]];
}

Swift 3+:

func presentationIndex(for pageViewController: UIPageViewController) -> Int {
        guard let index = viewControllers?.index(of: (pageViewController.viewControllers?.first)!) else { return 0 }
        return index
}

Sans la nécessité de se souvenir de l'index actuel. Où self.controllers est une NSArray de UIViewControllers affichée dans une UIPageViewController donnée. Je ne sais pas exactement comment fonctionne votre BSTCMWelcomingPageViewModel, mais il devrait être facile de l'ajuster.

6
micromanc3r

Solution Xamarin/C #

J'ai eu ce problème sous Xamarin, voici ma version de la solution de @ micromanc3r:

public class PageViewControllerDataSource : UIPageViewControllerDataSource
{
    UIViewController[] pages;

    public PageViewControllerDataSource(UIViewController[] pages)
    {
        this.pages = pages;
    }

...

    public override nint GetPresentationIndex(UIPageViewController pageViewController)
    {
        return Array.IndexOf(pages, pageViewController.ViewControllers[0]);
    }
}
2
Mark Moeykens
// ViewController.h File

#import <UIKit/UIKit.h>
#import "PageContentViewController.h"

@interface ViewScreen : UIViewController<UIPageViewControllerDataSource,UIPageViewControllerDelegate>

- (IBAction)Startwalkthrough:(id)sender;

@property(strong, nonatomic)UIPageViewController *pageViewController;
@property(strong, nonatomic)NSArray * pageTitles;
@property(strong,nonatomic)NSArray * pageImages;

@end

// ViewController.m File
#import "ViewScreen.h"

@interface ViewScreen ()

@end

@implementation ViewScreen

@synthesize pageTitles,pageImages;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    pageTitles =@[@"dianna",@"images",@"image",@"i1",@"hulk1",@"assasins"];
    pageImages =@[@"dianna",@"images",@"image",@"i1",@"hulk1",@"assasins"];

    self.pageViewController =[self.storyboard instantiateViewControllerWithIdentifier:@"PageViewController"];
    self.pageViewController.dataSource=self;

    PageContentViewController *startingViewController = [self viewControllerAtIndex:0];

    NSArray * viewController =@[startingViewController];

    [self.pageViewController setViewControllers:viewController direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];

    [self addChildViewController:_pageViewController];

    [self.view addSubview:_pageViewController.view];
    [self.pageViewController didMoveToParentViewController:self];


}

-(IBAction)Startwalkthrough:(id)sender
{
    PageContentViewController * startingViewController =[self viewControllerAtIndex:0];
    NSArray * viewControllers =@[startingViewController];
    [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];

}

- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
{
    if (([self.pageTitles count] == 0) || (index >= [self.pageTitles count])) {
        return nil;
    }

    // Create a new view controller and pass suitable data.
    PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageContentViewController"];
    pageContentViewController.imageFile = self.pageImages[index];
    pageContentViewController.titletext = self.pageTitles[index];
    pageContentViewController.pageIndex = index;

    return pageContentViewController;
}


#pragma mark - Page View Controller Data Source

-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
    NSUInteger index =((PageContentViewController *) viewController).pageIndex;
    if (index == NSNotFound) {
        return nil;
    }

    index--;
    if (index ==[self.pageTitles count]) {
        return  nil;

}
    return [self viewControllerAtIndex:index];

}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
    NSUInteger index = ((PageContentViewController*) viewController).pageIndex;

    if (index == NSNotFound) {
        return nil;
    }

    index++;
    if (index == [self.pageTitles count]) {
        return nil;
    }
    return [self viewControllerAtIndex:index];
}

-(NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController{
    return  [self.pageTitles count];
}

-(NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
    return  0;
}
@end


// Second File

PageViewController.h File 
#import <UIKit/UIKit.h>

@interface PageContentViewController : UIViewController

@property (strong, nonatomic) IBOutlet UILabel *txtLabel;
@property (strong, nonatomic) IBOutlet UIImageView *backgroundImageView;

@property NSUInteger pageIndex;
@property  NSString *titletext;
@property NSString * imageFile;
@end


// SecondFile.M File
#import "PageContentViewController.h"

@interface PageContentViewController ()

@end

@implementation PageContentViewController



-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self =[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        //
    }
    return  self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    self.backgroundImageView.image =[UIImage imageNamed:self.imageFile];
    self.txtLabel.text =self.titletext;

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end
0
Kiran Bhoraniya

Assurez-vous de définir le currentIndex AVANT d'appeler setViewControllers

0
apunn

Un indicateur de page sera visible si les deux méthodes sont implémentées, le style de transition est UIPageViewControllerTransitionStyleScroll et l'orientation de navigation est UIPageViewControllerNavigationOrientationHorizontal. Les deux méthodes sont appelées en réponse à un appel setViewControllers:..., mais l'index de présentation est mis à jour automatiquement dans le cas d'une navigation par gestes.

  • (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController NS_AVAILABLE_IOS(6_0);: nombre d'éléments reflétés dans l'indicateur de page.

  • (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController NS_AVAILABLE_IOS(6_0);: L'élément sélectionné reflété dans l'indicateur de page.

La réponse ci-dessus, donnée par aansul, fonctionne. 

Remarque: N'oubliez pas de définir le style de transition de pageViewController sur Scroll au lieu de Page Curl. Sinon, ça ne marchera pas. 

0
Hemanshu Liya

Swift 4.2

func presentationIndex(for pageViewController: UIPageViewController) -> Int {
    guard let currentController = pageViewController.viewControllers?.first else { 
     return 0 }
    guard let index = viewControllerList.index(of: currentController) else { return 0 }
    return index
}
0
Alexander