Можно ли программно перевернуть страницу в UIPageViewController?

Можно ли программно перевернуть страницу в UIPageViewController ?

Да, это возможно с помощью метода:

 - (void)setViewControllers:(NSArray *)viewControllers direction:(UIPageViewControllerNavigationDirection)direction animated:(BOOL)animated completion:(void (^)(BOOL finished))completion;` 

Это тот же метод, который используется для настройки первого controllerа представления на странице. Аналогично, вы можете использовать его для перехода на другие страницы.

Интересно, почему viewControllers – это массив, а не один controller?

Это связано с тем, что controller просмотра страницы может иметь «позвоночник» (например, в iBooks), одновременно отображая 2 страницы контента. Если вы одновременно показываете 1 страницу контента, просто передайте массив из 1 элемента.

Пример в Swift:

 pageContainer.setViewControllers([displayThisViewController], direction: .Forward, animated: true, completion: nil) 

Поскольку я тоже нуждался в этом, я расскажу подробнее о том, как это сделать.

Примечание. Предполагаю, что вы использовали стандартную форму шаблона для создания своей структуры UIPageViewController которая имеет как modelViewController и dataViewController созданные при ее вызове. Если вы не понимаете, что я написал, вернитесь назад и создайте новый проект, который использует UIPageViewController качестве основы. Тогда вы поймете.

Таким образом, для перехода на конкретную страницу необходимо настроить различные части метода, перечисленные выше. Для этого упражнения я предполагаю, что это пейзаж с двумя представлениями. Кроме того, я реализовал это как IBAction, чтобы его можно было сделать с помощью нажатия кнопки, а что нет – так же легко сделать селекторный вызов и передать нужные предметы.

Итак, для этого примера вам понадобятся два диспетчера представлений, которые будут отображаться – и, при желании, продвигаетесь ли вы вперед в книге или назад.

Обратите внимание, что я просто закодирован, где можно перейти на страницы 4 и 5 и использовать форматирование. Отсюда вы можете увидеть, что все, что вам нужно сделать, это передать переменные, которые помогут вам получить эти предметы …

 -(IBAction) flipToPage:(id)sender { // Grab the viewControllers at position 4 & 5 - note, your model is responsible for providing these. // Technically, you could have them pre-made and passed in as an array containing the two items... DataViewController *firstViewController = [self.modelController viewControllerAtIndex:4 storyboard:self.storyboard]; DataViewController *secondViewController = [self.modelController viewControllerAtIndex:5 storyboard:self.storyboard]; // Set up the array that holds these guys... NSArray *viewControllers = nil; viewControllers = [NSArray arrayWithObjects:firstViewController, secondViewController, nil]; // Now, tell the pageViewContoller to accept these guys and do the forward turn of the page. // Again, forward is subjective - you could go backward. Animation is optional but it's // a nice effect for your audience. [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL]; // Voila' - c'est fin! } 

Вот еще один пример кода для одного постраничного представления. Реализация для viewControllerAtIndex здесь опущена, она должна вернуть правильный controller представления для данного индекса.

 - (void)changePage:(UIPageViewControllerNavigationDirection)direction { NSUInteger pageIndex = ((FooViewController *) [_pageViewController.viewControllers objectAtIndex:0]).pageIndex; if (direction == UIPageViewControllerNavigationDirectionForward) { pageIndex++; } else { pageIndex--; } FooViewController *viewController = [self viewControllerAtIndex:pageIndex]; if (viewController == nil) { return; } [_pageViewController setViewControllers:@[viewController] direction:direction animated:YES completion:nil]; } 

Страницы могут быть изменены путем вызова

 [self changePage:UIPageViewControllerNavigationDirectionReverse]; [self changePage:UIPageViewControllerNavigationDirectionForward]; 

Спасибо, спасибо.

Это то, что я сделал с ним. Некоторые методы для перехода вперед или назад и один для перехода непосредственно к определенной странице. Его для 6-страничного документа в портретном режиме. Он будет работать нормально, если вы вставьте его в реализацию RootController шаблона pageViewController.

 -(IBAction)pageGoto:(id)sender { //get page to go to NSUInteger pageToGoTo = 4; //get current index of current page DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0]; NSUInteger retreivedIndex = [self.modelController indexOfViewController:theCurrentViewController]; //get the page(s) to go to DataViewController *targetPageViewController = [self.modelController viewControllerAtIndex:(pageToGoTo - 1) storyboard:self.storyboard]; DataViewController *secondPageViewController = [self.modelController viewControllerAtIndex:(pageToGoTo) storyboard:self.storyboard]; //put it(or them if in landscape view) in an array NSArray *theViewControllers = nil; theViewControllers = [NSArray arrayWithObjects:targetPageViewController, secondPageViewController, nil]; //check which direction to animate page turn then turn page accordingly if (retreivedIndex < (pageToGoTo - 1) && retreivedIndex != (pageToGoTo - 1)){ [self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL]; } if (retreivedIndex > (pageToGoTo - 1) && retreivedIndex != (pageToGoTo - 1)){ [self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:NULL]; } } -(IBAction)pageFoward:(id)sender { //get current index of current page DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0]; NSUInteger retreivedIndex = [self.modelController indexOfViewController:theCurrentViewController]; //check that current page isn't first page if (retreivedIndex < 5){ //get the page to go to DataViewController *targetPageViewController = [self.modelController viewControllerAtIndex:(retreivedIndex + 1) storyboard:self.storyboard]; //put it(or them if in landscape view) in an array NSArray *theViewControllers = nil; theViewControllers = [NSArray arrayWithObjects:targetPageViewController, nil]; //add page view [self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL]; } } -(IBAction)pageBack:(id)sender { //get current index of current page DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0]; NSUInteger retreivedIndex = [self.modelController indexOfViewController:theCurrentViewController]; //check that current page isn't first page if (retreivedIndex > 0){ //get the page to go to DataViewController *targetPageViewController = [self.modelController viewControllerAtIndex:(retreivedIndex - 1) storyboard:self.storyboard]; //put it(or them if in landscape view) in an array NSArray *theViewControllers = nil; theViewControllers = [NSArray arrayWithObjects:targetPageViewController, nil]; //add page view [self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:NULL]; } } 

Я мог бы вообще что-то упустить, но это решение кажется намного проще, чем многие другие.

 extension UIPageViewController { func goToNextPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) { if let currentViewController = viewControllers?[0] { if let nextPage = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) { setViewControllers([nextPage], direction: .forward, animated: animated, completion: completion) } } } } 

Как насчет использования методов из dataSource?

 UIViewController *controller = [pageViewController.dataSource pageViewController:self.pageViewController viewControllerAfterViewController:pageViewController.viewControllers.firstObject]; [pageViewController setViewControllers:@[controller] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil]; 

Аналогично для обратной.

В Свифт :

 import UIKit extension HomeViewController { // MARK: - Carousel management. func startTimerForMovingCarousel(let numberOfSecondsBetweenFiringsOfTheTimer: NSTimeInterval) { if (self.timerForMovingCarousel == nil) { self.timerForMovingCarousel = NSTimer.scheduledTimerWithTimeInterval(numberOfSecondsBetweenFiringsOfTheTimer, target: self, selector: "moveCarousel", userInfo: nil, repeats: true) } } func moveCarousel() { println("I move the carousel.") let currentContentViewControllerDisplayed = self.pageViewController!.viewControllers[0] as! ContentViewController var index: Int = currentContentViewControllerDisplayed.index if index == self.arrayViewControllers.count - 1 { index = 0 } else { ++index } let contentViewControllerToDisplay = self.arrayViewControllers[index] as! ContentViewController self.pageViewController.setViewControllers([contentViewControllerToDisplay], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil) self.pageControl.currentPage = contentViewControllerToDisplay.index } func invalidateTimerForMovingCarousel() { if (self.timerForMovingCarousel != nil) { self.timerForMovingCarousel.invalidate() self.timerForMovingCarousel = nil } } } 

Swift 4:

Мне нужно было перейти к следующему controllerу, когда я нажимаю следующий на controllerе представления pagecontroller, а также обновляю индекс pageControl, поэтому это было лучшее и самое простое решение для меня :

 let pageController = self.parent as! PageViewController pageController.setViewControllers([parentVC.orderedViewControllers[1]], direction: .forward, animated: true, completion: nil) pageController.pageControl.currentPage = 1 

Однако использование этого метода вызова self.pageViewController setViewControllers не вызывает «viewDidDissapear» на viewController для страницы, которая была отклонена, тогда как ручная перемотка страницы вызывает callDidDissapear на повернутой странице. Я считаю, что это причина моего крушения

«Количество controllerов представления (0) не соответствует требуемому числу (1) для запрошенного перехода»

Мне также понадобилась кнопка для навигации по левой стороне на PageViewController, которая должна делать именно то, что вы ожидаете от движения салфетки.

Поскольку у меня было несколько правил, уже установленных внутри « pageViewController: viewControllerBeforeViewController » для работы с естественной навигацией по навигации, я хотел, чтобы кнопка повторно использовала весь этот код и просто не могла позволить себе использовать определенные индексы для доступа к страницам как предыдущие ответы сделали. Поэтому мне пришлось принять альтернативное решение.

Обратите внимание, что следующий код предназначен для controllerа просмотра страниц, который является свойством внутри моего настраиваемого ViewController, и его позвоночник установлен в середине.

Вот код, который я написал для моей кнопки «Навигация слева»:

 - (IBAction)btnNavigateLeft_Click:(id)sender { // Calling the PageViewController to obtain the current left page UIViewController *currentLeftPage = [_pageController.viewControllers objectAtIndex:0]; // Creating future pages to be displayed NSArray *newDisplayedPages = nil; UIViewController *newRightPage = nil; UIViewController *newLeftPage = nil; // Calling the delegate to obtain previous pages // My "pageViewController:viewControllerBeforeViewController" method returns nil if there is no such page (first page of the book). newRightPage = [self pageViewController:_pageController viewControllerBeforeViewController:currentLeftPage]; if (newRightPage) { newLeftPage = [self pageViewController:_pageController viewControllerBeforeViewController:newRightPage]; } if (newLeftPage) { newDisplayedPages = [[NSArray alloc] initWithObjects:newLeftPage, newRightPage, nil]; } // If there are two new pages to display, show them with animation. if (newDisplayedPages) { [_pageController setViewControllers:newDisplayedPages direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:nil]; } } 

Вы можете сделать что-то очень похожее, чтобы сделать правильную навигационную кнопку отсюда.

Для одной страницы я только что отредактировал ответ @Jack Humphries

 -(void)viewDidLoad { counter = 0; } -(IBAction)buttonClick:(id)sender { counter++; DataViewController *secondVC = [self.modelController viewControllerAtIndex:counter storyboard:self.storyboard]; NSArray *viewControllers = nil; viewControllers = [NSArray arrayWithObjects:secondVC, nil]; [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL]; } 

В случае, если PAGE CONTROL, чтобы указать текущую страницу, – это O &&. Вы хотите, чтобы страницы перемещались по прокрутке, а также нажатием пользовательских кнопок в Page ViewController, ниже может оказаться полезным.

 //Set Delegate & Data Source for PageView controller [Say in View Did Load] self.pageViewController.dataSource = self; self.pageViewController.delegate = self; // Delegates called viewControllerBeforeViewController when User Scroll to previous page - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController{ [_nextBtn setTitle:@"Next" forState:UIControlStateNormal]; NSUInteger index = ((PageContentViewController*) viewController).pageIndex; if (index == NSNotFound){ return nil; }else if (index > 0){ index--; }else{ return nil; } return [self viewControllerAtIndex:index]; } 

// Делегирование называется viewControllerAfterViewController, когда пользователь переходит к следующей странице

 - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController{ NSUInteger index = ((PageContentViewController*) viewController).pageIndex; if (index == NSNotFound){ return nil; }else if (index < 3){ index++; }else{ return nil; } return [self viewControllerAtIndex:index];} //Delegate called while transition of pages. The need to apply logic in this delegate is to maintain the index of current page. - (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers{ buttonIndex = (int)((PageContentViewController*) pendingViewControllers.firstObject).pageIndex; 

}

 -(void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{ if (buttonIndex == 0){ _backButton.hidden = true; }else if (buttonIndex == [self.pageImages count] - 1){ _backButton.hidden = false; [_nextBtn setTitle:@"Begin" forState:UIControlStateNormal]; }else{ _backButton.hidden = false; } 

}

// Пользовательская кнопка (Prev & next) Логика

 -(void)backBtnClicked:(id)sender{ if (buttonIndex > 0){ buttonIndex -= 1; } if (buttonIndex < 1) { _backButton.hidden = YES; } if (buttonIndex >=0) { [_nextBtn setTitle:@"Next" forState:UIControlStateNormal]; PageContentViewController *startingViewController = [self viewControllerAtIndex:buttonIndex]; NSArray *viewControllers = @[startingViewController]; [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil]; } 

}

 -(void)nextBtnClicked:(id)sender{ if (buttonIndex < 3){ buttonIndex += 1; } if(buttonIndex == _pageImages.count){ //Navigate Outside Pageview controller }else{ if (buttonIndex ==3) { [_nextBtn setTitle:@"Begin" forState:UIControlStateNormal]; } _backButton.hidden = NO; PageContentViewController *startingViewController = [self viewControllerAtIndex:buttonIndex]; NSArray *viewControllers = @[startingViewController]; [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil]; } 

}

 //BUTTON INDEX & MAX COUNT -(NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController{ return [self.pageImages count];} -(NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController{ return buttonIndex;} 
 - (void)moveToPage { NSUInteger pageIndex = ((ContentViewController *) [self.pageViewController.viewControllers objectAtIndex:0]).pageIndex; pageIndex++; ContentViewController *viewController = [self viewControllerAtIndex:pageIndex]; if (viewController == nil) { return; } [self.pageViewController setViewControllers:@[viewController] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil]; } 

// теперь вызываем этот метод

[self moveToPage];

Надеюсь это работает 🙂

Как отметил @samwize, способ разбивки на страницы заключается в использовании

 setViewControllers:array 

Вот как я это сделал: у меня есть источник данных и делегат отдельно. Вы можете вызвать этот метод и изменить только «следующий» вид. Раньше вам приходилось применять правила поискового вызова. То есть вы должны проверить направление и следующий controller. Если вы используете этот метод с вашим настраиваемым источником данных, массив controllerов, который вы показываете, не изменится (поскольку вы будете использовать настраиваемый массив в подclassе NSObject).

Используя собственный источник данных, метод просто устанавливает новое представление (с определенным направлением). Так как вы все равно будете контролировать страницы, которые будут отображаться при обычном прокрутке.

Я работаю над этим со вчерашнего дня, и я, наконец, сделал это. Я не мог использовать стандартный шаблон полностью, потому что у меня есть три разных viewControllers как childviews:

 1 - rootViewController; 2 - model; 3 - viewControllers 3.1 - VC1; 3.2 - VC2; 3.3 - VC3. Note: all of VCs has Storyboard ID. 

Мне нужна кнопка триггера только в первом VC, поэтому я добавил одно свойство для pageViewController и model:

 #import  #import "Model.h" @interface VC1 : UIViewController @property (nonatomic, strong) UIPageViewController *thePageViewController; @property (nonatomic, strong) SeuTimePagesModel *theModel; @end 

Я переписал метод init модели, чтобы передать раскадровку и pageViewController в качестве параметров, поэтому я мог бы установить их в свой VC1:

 - (id)initWithStoryboard:(UIStoryboard *)storyboard andPageViewController:(UIPageViewController *)controller { if (self = [super init]) { VC1 *vc1 = [storyboard instantiateViewControllerWithIdentifier:@"VC1"]; vc1.pageViewController = controller; vc1.model = self; VC2 *vc2 = [storyboard instantiateViewControllerWithIdentifier:@"VC2"]; VC3 *vc3 = [storyboard instantiateViewControllerWithIdentifier:@"VC3"]; self.pageData = [[NSArray alloc] initWithObjects:vc1, vc2, vc3, nil]; } return self; } 

Наконец, я добавил IBAction в свой vc1, чтобы вызвать метод pageViewController setViewControllers: direction: animated: completion ::

 - (IBAction)go:(id)sender { VC2 *vc2 = [_model.pages objectAtIndex:1]; NSArray *viewControllers = @[vc2]; [_pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil]; } 

Примечание. Мне не нужно находить индексы VCs, моя кнопка возвращает меня ко второму VC, но не сложно получить все индексы и отслеживать ваши детские просмотры:

 - (IBAction)selecionaSeuTime:(id)sender { NSUInteger index = [_model.pages indexOfObject:self]; index++; VC2 *vc2 = [_model.pages objectAtIndex:1]; NSArray *viewControllers = @[vc2]; [_pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil]; } 

Надеюсь, это поможет вам!

  • Есть ли способ удалить разделительную линию из UITableView?
  • Цвет кнопки UIActionSheet
  • Возможно открытие всплывающих ссылок в UIWebView?
  • iOS - Отключение клавиатуры при касании вне UITextField
  • Просмотр controllerов: как программно переключаться между представлениями?
  • Как нарисовать границу вокруг UILabel?
  • Как я могу округлить значение float до двух постсимвольных позиций?
  • Как использовать UIPageControl для создания нескольких видов?
  • Изменить размер шрифта для заполнения UITextView?
  • Как рассчитать ширину текстовой строки определенного шрифта и размера шрифта?
  • Получение значения альфа-пикселя для UIImage
  • Давайте будем гением компьютера.