62
задан 16 July 2015 в 13:53

13 ответов

Программирование iOS6 , Matt Neuburg документирует эту точную проблему, и я на самом деле нашел, что его решение чувствует себя немного лучше, чем в настоящее время принимаемый ответ. То решение, которое работает отлично, имеет отрицательный побочный эффект анимации к изображению прежде/после того, как, и затем резко замена той страницы с желаемой страницей. Я чувствовал, что это было странным пользовательским опытом, и решение Matt заботится об этом.

__weak UIPageViewController* pvcw = pvc;
[pvc setViewControllers:@[page]
              direction:UIPageViewControllerNavigationDirectionForward
               animated:YES completion:^(BOOL finished) {
                   UIPageViewController* pvcs = pvcw;
                   if (!pvcs) return;
                   dispatch_async(dispatch_get_main_queue(), ^{
                       [pvcs setViewControllers:@[page]
                                  direction:UIPageViewControllerNavigationDirectionForward
                                   animated:NO completion:nil];
                   });
               }];
84
ответ дан 31 October 2019 в 13:35
    let orderedViewControllers = [UIViewController(),UIViewController(), UIViewController()]
    let pageViewController = UIPageViewController()
    let pageControl = UIPageControl()

    func jump(to: Int, completion: @escaping (_ vc: UIViewController?) -> Void){

        guard orderedViewControllers.count > to else{
            //index of bounds
            return
        }

        let toVC = orderedViewControllers[to]

        var direction: UIPageViewController.NavigationDirection = .forward

        if pageControl.currentPage < to {
            direction = .forward;
        } else {
            direction = .reverse;
        }

        pageViewController.setViewControllers([toVC], direction: direction, animated: true) { _ in
            DispatchQueue.main.async {
                self.pageViewController.setViewControllers([toVC], direction: direction, animated: false){ _ in
                    self.pageControl.currentPage = to
                        completion(toVC)

                }
            }
        }
    }

ИСПОЛЬЗОВАНИЕ:

self.jump(to: 5) { (vc) in
    // you can do anything for new vc.
}
0
ответ дан 31 October 2019 в 13:35

Я боролся с этой проблемой в течение долгого времени сам. Для меня у меня был UIPageViewController (я звонил, это PageController) загружаются от раскадровки, и на нем я добавляю UIViewController 'ContentVC'.

я позволяю ContentVC, заботится о данных, которые будут загружены на предметной области и позволят PageController, заботится об обновлениях sliding/goto/PageIndicator. ContentVC имеет ivar CurrentPageIndex и отправляет то значение PageController, таким образом, PageController знает, какая страница это идет. В моем.m файле, который имеет PageController, у меня есть эти два метода.

Примечание, что я привык набор для 0 и так каждый раз перезагрузки PageVC, это переходит к первой странице, которую я не хочу, [сам viewControllerAtIndex:0].

- (void)setPageForward
{  
  ContentVC *FirstVC = [self viewControllerAtIndex:[CurrentPageIndex integerValue]];

  NSArray *viewControllers = @[FirstVC];
  [PageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
}

Этот второй метод является методом DataSource PageViewController. presentationIndexForPageViewController установит выделенную точку на правильную страницу (страница, которую Вы хотите). Обратите внимание, что, если мы возвращаемся 0 сюда, индикатор страницы выделит первую точку, которая указывает на первую страницу, и мы не хотим это.

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController 
{
  return [CurrentPageIndex integerValue];
}
0
ответ дан 31 October 2019 в 13:35

Вот актуальный Swift 3 + версия ответ @djibouti33 с очищенным синтаксисом.

weak var weakPageVc = pageVc

pageVc.setViewControllers([page], direction: .forward, animated: true) { finished in
    guard let pageVc = weakPageVc else {
        return
    }

    DispatchQueue.main.async {
        pageVc.setViewControllers([page], direction: .forward, animated: false)
    }
}
1
ответ дан 31 October 2019 в 13:35

Это - только решение

-(void)buyAction
{
    isFromBuy = YES;
    APPChildViewController *initialViewController = [self viewControllerAtIndex:4];
    viewControllers = [NSArray arrayWithObject:initialViewController];
    [self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
}

-(NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController 
{
    if (isFromBuy) {
        isFromBuy = NO;
        return 5;
    }
    return 0;
}
2
ответ дан 31 October 2019 в 13:35

Важно отметить, что это больше не имеет место в iOS 10, и Вы больше не должны использовать принятое решение для ответа. Только продолжите как всегда.

3
ответ дан 31 October 2019 в 13:35

Быстрая версия ответа djibouti33:

weak var pvcw = pageViewController
pageViewController!.setViewControllers([page], direction: UIPageViewControllerNavigationDirection.Forward, animated: true) { _ in
        if let pvcs = pvcw {
            dispatch_async(dispatch_get_main_queue(), {
                pvcs.setViewControllers([page], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
            })
        }
    }
3
ответ дан 31 October 2019 в 13:35

Вот мое решение Swift, которое будет использоваться для подклассов UIPageViewController:

Предполагают, что Вы храните массив viewControllers в viewControllerArray и текущего индекса страницы в updateCurrentPageIndex.

  private func slideToPage(index: Int, completion: (() -> Void)?) {
    let tempIndex = currentPageIndex
    if currentPageIndex < index {
      for var i = tempIndex+1; i <= index; i++ {
        self.setViewControllers([viewControllerArray[i]], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: {[weak self] (complete: Bool) -> Void in
          if (complete) {
            self?.updateCurrentPageIndex(i-1)
            completion?()
          }
          })
      }
    }
    else if currentPageIndex > index {
      for var i = tempIndex - 1; i >= index; i-- {
        self.setViewControllers([viewControllerArray[i]], direction: UIPageViewControllerNavigationDirection.Reverse, animated: true, completion: {[weak self] (complete: Bool) -> Void in
          if complete {
            self?.updateCurrentPageIndex(i+1)
            completion?()
          }
          })
      }
    }
  }
5
ответ дан 31 October 2019 в 13:35

Если Вы не должны анимировать к новой странице, поскольку я не сделал, следующий код работал на меня, обратился "к Значению, Измененному" в раскадровке. Вместо того, чтобы измениться между контроллерами представления, я изменяю данные, связанные с контроллером текущего представления.

    - (IBAction)pageControlCurrentPageDidChange:(id)sender
{
    self.currentIndex = self.pageControl.currentPage;
    MYViewController *currentPageViewController = (MYViewController *)self.pageViewController.viewControllers.firstObject;
    currentPageViewController.pageData = [self.pageDataSource dataForPage:self.currentIndex];
    [currentPageViewController updateDisplay];
}

currentIndex там, таким образом, я могу обновить currentPage pageControl, когда я сильно ударяю между страницами.

pageDataSource dataForPage: возвращает массив объектов данных, которые отображены страницами.

1
ответ дан 31 October 2019 в 13:35

У меня был другой подход, должно быть возможным, если Ваши страницы разработаны, чтобы быть обновленными после init:
, Когда страница руководства выбрана, я обновляю флаг

- (void)scrollToPage:(NSInteger)page animated:(BOOL)animated
{
    if (page != self.currentPage) {
        [self setViewControllers:@[[self viewControllerForPage:page]]
                       direction:(page > self.currentPage ?
                                  UIPageViewControllerNavigationDirectionForward :
                                  UIPageViewControllerNavigationDirectionReverse)
                        animated:animated
                      completion:nil];
        self.currentPage = page;
        self.forceReloadNextPage = YES; // to override view controller automatic page cache
    }
}

- (ScheduleViewController *)viewControllerForPage:(NSInteger)page
{
    CustomViewController * scheduleViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"CustomViewController"];
    scheduleViewController.view.tag = page; // keep track of pages using view.tag property
    scheduleViewController.data = [self dataForPage:page];

    if (self.currentViewController)
        scheduleViewController.calendarLayoutHourHeight = self.currentViewController.calendarLayoutHourHeight;

    return scheduleViewController;
}

и затем вынуждаю следующую страницу перезагрузить с корректными данными:

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers
{
    CustomViewController * nextViewController = [pendingViewControllers lastObject];

    // When manual scrolling occurs, the next page is loaded from UIPageViewController cache
    //  and must be refreshed
    if (self.forceReloadNextPage) {
        // calculate the direction of the scroll to know if to load next or previous page
        NSUInteger page = self.currentPage + 1;
        if (self.currentPage > nextViewController.view.tag) page = self.currentPage - 1;

        nextViewController.data = [self dataForPage:page];
        self.forceReloadNextPage = NO;
    }
}
1
ответ дан 31 October 2019 в 13:35

Я использую эту функцию (я всегда нахожусь в среде, 2 постраничных режимах)

-(void) flipToPage:(NSString * )index {


int x = [index intValue];
LeafletPageContentViewController *theCurrentViewController = [self.pageViewController.viewControllers   objectAtIndex:0];

NSUInteger retreivedIndex = [self indexOfViewController:theCurrentViewController];

LeafletPageContentViewController *firstViewController = [self viewControllerAtIndex:x];
LeafletPageContentViewController *secondViewController = [self viewControllerAtIndex:x+1 ];


NSArray *viewControllers = nil;

viewControllers = [NSArray arrayWithObjects:firstViewController, secondViewController, nil];


if (retreivedIndex < x){

    [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];

} else {

    if (retreivedIndex > x ){

        [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:NULL];
      } 
    }
} 
5
ответ дан 31 October 2019 в 13:35

Таким образом, я столкнулся с той же проблемой как Вы, где я должен был смочь 'перейти' к странице и затем нашел 'порядок испорченным', когда я жестикулировал назад страница. Насколько я смог сказать, контроллер просмотра страницы определенно кэширует контроллеры представления и когда Вы 'переходите' к странице, необходимо указать направление: передайте или инвертируйте. Это затем предполагает, что новый контроллер представления является 'соседом' предыдущего контроллера представления и следовательно автоволшебно представляет предыдущий контроллер представления, когда Вы жестикулируете назад. Я нашел, что это только происходит, когда Вы используете UIPageViewControllerTransitionStyleScroll а не UIPageViewControllerTransitionStylePageCurl. Стиль завихрения страницы, по-видимому, не делает того же кэширования с тех пор, если Вы 'переходите' к странице и затем жесту назад, это поставляет эти pageViewController:viewController(Before/After)ViewController: сообщение к источнику данных, позволяющему Вам обеспечить корректный соседний контроллер представления.

Решение: Когда выполнение 'перехода' для подкачки страниц Вас может сначала перейти к соседней странице к странице (animated:NO), Вы переходите к и затем в блоке завершения того перехода, перехода к желаемой странице. Это обновит кэш, таким образом, что, когда Вы жестикулируете назад, корректная соседняя страница будет отображена. Оборотная сторона - то, что необходимо будет создать два контроллера представления; тот, который Вы переходите к и тот, который должен быть отображен после жестикулирования назад.

Вот код к категории, которую я записал для UIPageViewController:

@implementation UIPageViewController (Additions)

 - (void)setViewControllers:(NSArray *)viewControllers direction:(UIPageViewControllerNavigationDirection)direction invalidateCache:(BOOL)invalidateCache animated:(BOOL)animated completion:(void (^)(BOOL finished))completion {
    NSArray *vcs = viewControllers;
    __weak UIPageViewController *mySelf = self;

    if (invalidateCache && self.transitionStyle == UIPageViewControllerTransitionStyleScroll) {
        UIViewController *neighborViewController = (direction == UIPageViewControllerNavigationDirectionForward
                                                    ? [self.dataSource pageViewController:self viewControllerBeforeViewController:viewControllers[0]]
                                                    : [self.dataSource pageViewController:self viewControllerAfterViewController:viewControllers[0]]);
        [self setViewControllers:@[neighborViewController] direction:direction animated:NO completion:^(BOOL finished) {
            [mySelf setViewControllers:vcs direction:direction animated:animated completion:completion];
        }];
    }
    else {
        [mySelf setViewControllers:vcs direction:direction animated:animated completion:completion];
    }
}

@end

то, Что можно сделать для тестирования этого, создают новое 'Основанное на странице Приложение' и добавляют 'goto' кнопку, которая 'перейдет' к определенному календарному месяцу и затем жесту назад. Обязательно установите стиль перехода для прокрутки.

37
ответ дан 31 October 2019 в 13:35

Я могу подтвердить эту проблему, и что это только происходит при использовании UIPageViewControllerTransitionStyleScroll а не UIPageViewControllerTransitionStylePageCurl.

Обходное решение: Делают цикл и вызов UIPageViewController setViewControllers для каждого поворота страницы, пока Вы не достигаете желаемой страницы.

Это сохраняет внутренний индекс источника данных в UIPageViewController в синхронизации.

2
ответ дан 31 October 2019 в 13:35

Другие вопросы по тегам:

Похожие вопросы: