UIPageViewController: вернуть текущий видимый вид - PullRequest
87 голосов
/ 06 декабря 2011

Как вы узнаете, какая текущая страница / представление отображается внутри UIPageViewController?

Я переопределил метод viewDidAppear моих дочерних представлений, чтобы они отправляли идентификатор в родительское представление.в их методе viewDidAppear.

Однако проблема заключается в следующем: я не могу надежно использовать этот идентификатор в качестве идентификатора для отображаемой страницы.потому что, если пользователь переворачивает страницу, но на полпути решает остановить поворот и вернуть страницу назад, viewDidAppear уже будет вызван.(вид виден за скрученной страницей).

Может быть, я должен переключиться на новый идентификатор, только если текущий вид исчезнет.Но мне интересно, если нет более простого способа вернуть вид, который в настоящее время видим?

Ответы [ 20 ]

100 голосов
/ 06 декабря 2011

Вы должны вручную отслеживать текущую страницу.Метод делегата pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted: сообщит вам, когда обновить эту переменную.Последний аргумент метода transitionCompleted: может сообщить вам, завершил ли пользователь переход на страницу или нет.

57 голосов
/ 11 апреля 2013

Начиная с iOS 6, я обнаружил, что свойство viewControllers UIPageViewController постоянно обновляется, так что оно всегда будет содержать один контроллер представления, представляющий текущую страницу, и ничего больше.Таким образом, вы можете получить доступ к текущей странице, вызвав viewControllers[0] (при условии, что вы одновременно показываете только один контроллер представления).

Массив viewController обновляется только после того, как страница «защелкивается», поэтому, если пользовательрешает частично раскрыть следующую страницу, она не становится "текущей" страницей, пока они не завершат переход.

Если вы хотите отслеживать «номера страниц», присвойте контроллерам представления индексное значение при их создании с помощью методов источника данных UIPageViewController.


Так, например:

-(void)autoAdvance
    {
    UIViewController *currentVC = self.viewControllers[0];
    NSUInteger currentIndex = [myViewControllers indexOfObject:currentVC];

    if ( currentIndex >= (myViewControllers.count-1) ) return;

    [self setViewControllers:@[myViewControllers[ currentIndex+1 ]]
        direction:UIPageViewControllerNavigationDirectionForward
        animated:YES
        completion:nil];
    }
-(NSInteger)presentationIndexForPageViewController:
                         (UIPageViewController *)pageViewController
    {
    // return 0;
    UIViewController *currentVC = self.viewControllers[0];
    NSUInteger currentIndex = [myViewControllers indexOfObject:currentVC];
    return currentIndex;
    }

Но обратите внимание на комментарии , что это ненадежно.

45 голосов
/ 12 марта 2014

К сожалению, все вышеперечисленные методы мне не помогли.Тем не менее, я нашел решение с помощью тегов.Может быть, он не самый лучший, но он работает и надеюсь, что кому-то поможет:

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed 
{
    if (completed) {
        int currentIndex = ((UIViewController *)self.pageViewController.viewControllers.firstObject).view.tag;
        self.pageControl.currentPage = currentIndex;
    }
}

В Swift: (спасибо @ Jessy )

func pageViewController(pageViewController: UIPageViewController,
    didFinishAnimating finished: Bool,
    previousViewControllers: [UIViewController],
    transitionCompleted completed: Bool)
{
    guard completed else { return }
    self.pageControl.currentPage = pageViewController.viewControllers!.first!.view.tag
}

Пример: Гист

34 голосов
/ 28 марта 2013

Опираясь на ответ Оле…

Вот как я реализовал 4 метода для отслеживания текущей страницы и обновления индикатора страницы до правильного индекса:

- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController{

    return (NSInteger)[self.model count];

}

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController{

    return (NSInteger)self.currentIndex;
}

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers{

    SJJeanViewController* controller = [pendingViewControllers firstObject];
    self.nextIndex = [self indexOfViewController:controller];

}

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{

    if(completed){

        self.currentIndex = self.nextIndex;

    }

    self.nextIndex = 0;

}
31 голосов
/ 22 июня 2013

Решение ниже работает для меня.

Apple может избежать многих хлопот, сделав более настраиваемую нумерацию страниц прокрутки UIPageViewController.Мне пришлось прибегнуть к наложению новых UIView и UIPageControl только потому, что встроенная нумерация страниц UIPageViewController не будет поддерживать прозрачный фон или изменение положения в пределах рамки просмотра.

- (void)pageViewController:(UIPageViewController *)pvc didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
  if (!completed)
  {
    return;
  }
  NSUInteger currentIndex = [[self.pageViewController.viewControllers lastObject] index];
  self.pageControl.currentPage = currentIndex;
}
17 голосов
/ 28 октября 2016

Swift 4

Нет ненужного кода.3 способа сделать это.Использование метода UIPageViewControllerDelegate .

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    guard completed else { return }

    // using content viewcontroller's index
    guard let index = (pageViewController.viewControllers?.first as? ContentViewController)?.index else { return }

    // using viewcontroller's view tag
    guard let index = pageViewController.viewControllers?.first?.view.tag else { return }

    // switch on viewcontroller
    guard let vc = pageViewController.viewControllers?.first else { return }
    let index: Int
    switch vc {
    case is FirstViewController:
        index = 0
    case is SecondViewController:
        index = 1
    default:
        index = 2
    }
}
11 голосов
/ 09 февраля 2012

Я отслеживаю индекс страницы, используя небольшую функцию и определяя pageIndex как статический NSInteger.

-(void) setPageIndex
{
    DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0];

    pageIndex = [self.modelController indexOfViewController:theCurrentViewController];
}

и вызов [self setPageIndex]; внутри функции, указанной Ole, а также после обнаружения изменения ориентации.

5 голосов
/ 05 апреля 2013

Сначала я использовал решение Corey, но оно не работало на iOS5, а затем закончил с использованием

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{

    if(completed) {
        _currentViewController = [pageViewController.viewControllers lastObject];
    }
}

Он пытался переключаться между разными страницами, и сейчас он работает хорошо.

3 голосов
/ 20 ноября 2015

К сожалению, ничто из вышеперечисленного не работает для меня.

У меня есть два контроллера вида, и когда я немного (около 20 пикселей) прокручиваю последний вид назад, это вызывает делегата:

pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

и говорят, что текущая страница (индекс) является 0, что неверно.

Использование делегата внутри дочернего viewController что-то вроде:

- (void)ViewController:(id)VC didShowWithIndex:(long)page;

// and a property

@property (nonatomic) NSInteger index;

, который вызывается внутри viewDidAppear вроде:

- (void)viewDidAppear:(BOOL)animated
{
    ...

    [self.delegate ViewController:self didShowWithIndex:self.index];
}

Работал на меня.

2 голосов
/ 08 февраля 2016

Это работает для меня надежно

У меня есть пользовательский UIPageController.Этот pageController.currentPage обновляется из отображаемого UIViewController в viewWillAppear

   var delegate: PageViewControllerUpdateCurrentPageNumberDelegate?

      init(delegate: PageViewControllerUpdateCurrentPageNumberDelegate ){
        self.delegate = delegate
        super.init(nibName: nil, bundle: nil)
      }

      required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }

    override func viewWillAppear(animated: Bool) {

        if delegate != nil {
          self.delegate!.upateCurrentPageNumber(0) //(0) is the pageNumber corresponding to the displayed controller
        }
      } 

    //In the pageViewController 

    protocol PageViewControllerUpdateCurrentPageNumberDelegate {

      func upateCurrentPageNumber(currentPageIndex: Int)
    }

     create the view display controllers initializing with the delegate

    orderedViewControllers = {
              return [
                IntroductionFirstPageViewController(delegate: self),
                IntroductionSecondPageViewController(delegate: self),
                IntroductionThirdPageViewController(delegate: self)
              ]

            }()

    the function implementing the protocol

    func upateCurrentPageNumber(currentPageIndex: Int){
        pageControl.currentPage = currentPageIndex
      }
...