Изменение страницы UIPageViewController программно не обновляет UIPageControl

В моем обычном классе UIPageViewController:

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

Затем я программно устанавливаю текущий ViewController при нажатии кнопки:

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

Если я не могу сделать это с UIPageControl, который "принадлежит" моему UIPageViewController, я просто попытаюсь сделать свое. Но было бы неплохо, если бы это было возможно!

Ответ 1

чтобы обновить индикатор UIPageControl, вам необходимо реализовать один метод источника данных UIPageViewController (метод UIPageViewControllerDataSource):

-(NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController

Этот метод отвечает за обновление индикатора управления страницей (при использовании UIPageViewController). Вам нужно вернуть значение текущей страницы в этот метод. Метод вызывается по умолчанию, когда вы используете/выполняете вызов setViewControllers в своем пользовательском UIPageViewController.

Итак, фрагмент кода, который вам нужно написать, это:

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

Надеюсь, это решает вашу проблему.:)

Ответ 2

Как уже упоминалось в принятом ответе, вам нужно реализовать

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController

Но для меня было достаточно использовать его вот так:

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

Без необходимости помнить текущий индекс. Где self.controllers - это NSArray of UIViewControllers, отображаемое в данном UIPageViewController. Я не уверен, как работает ваш BSTCMWelcomingPageViewModel, но его нужно легко настроить.

Ответ 3

Решение Xamarin/С#

У меня была эта проблема в Xamarin, вот моя версия решения @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]);
    }
}

Ответ 4

Индикатор страницы будет виден, если оба метода реализованы, стиль перехода UIPageViewControllerTransitionStyleScroll, а ориентация навигации UIPageViewControllerNavigationOrientationHorizontal. Оба метода вызываются в ответ на вызов setViewControllers:..., но индекс представления автоматически обновляется в случае навигации с помощью жестов.

  • (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController NS_AVAILABLE_IOS(6_0);: количество элементов, отображаемых на индикаторе страницы.

  • (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController NS_AVAILABLE_IOS(6_0);: выбранный элемент отражен в индикаторе страницы.

Ответ выше, заданный аансулом, работает.

Примечание. Не забудьте установить стиль перехода к экрану pageViewController для прокрутки вместо зависания страницы. Иначе это не сработает.

Ответ 5

// 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 [email protected][@"dianna",@"images",@"image",@"i1",@"hulk1",@"assasins"];
    pageImages [email protected][@"dianna",@"images",@"image",@"i1",@"hulk1",@"assasins"];

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

    PageContentViewController *startingViewController = [self viewControllerAtIndex:0];

    NSArray * viewController [email protected][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 [email protected][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

Ответ 6

Обязательно установите currentIndex ПЕРЕД вызовом setViewControllers