Программирование 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];
});
}];
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.
}
Я боролся с этой проблемой в течение долгого времени сам. Для меня у меня был 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];
}
Вот актуальный 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)
}
}
Это - только решение
-(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;
}
Важно отметить, что это больше не имеет место в iOS 10, и Вы больше не должны использовать принятое решение для ответа. Только продолжите как всегда.
Быстрая версия ответа 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)
})
}
}
Вот мое решение 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?()
}
})
}
}
}
Если Вы не должны анимировать к новой странице, поскольку я не сделал, следующий код работал на меня, обратился "к Значению, Измененному" в раскадровке. Вместо того, чтобы измениться между контроллерами представления, я изменяю данные, связанные с контроллером текущего представления.
- (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: возвращает массив объектов данных, которые отображены страницами.
У меня был другой подход, должно быть возможным, если Ваши страницы разработаны, чтобы быть обновленными после 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;
}
}
Я использую эту функцию (я всегда нахожусь в среде, 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];
}
}
}
Таким образом, я столкнулся с той же проблемой как Вы, где я должен был смочь 'перейти' к странице и затем нашел 'порядок испорченным', когда я жестикулировал назад страница. Насколько я смог сказать, контроллер просмотра страницы определенно кэширует контроллеры представления и когда Вы 'переходите' к странице, необходимо указать направление: передайте или инвертируйте. Это затем предполагает, что новый контроллер представления является 'соседом' предыдущего контроллера представления и следовательно автоволшебно представляет предыдущий контроллер представления, когда Вы жестикулируете назад. Я нашел, что это только происходит, когда Вы используете 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' кнопку, которая 'перейдет' к определенному календарному месяцу и затем жесту назад. Обязательно установите стиль перехода для прокрутки.
Я могу подтвердить эту проблему, и что это только происходит при использовании UIPageViewControllerTransitionStyleScroll
а не UIPageViewControllerTransitionStylePageCurl
.
Обходное решение: Делают цикл и вызов UIPageViewController setViewControllers
для каждого поворота страницы, пока Вы не достигаете желаемой страницы.
Это сохраняет внутренний индекс источника данных в UIPageViewController в синхронизации.