Відповіді:
Так, це можливо методом:
- (void)setViewControllers:(NSArray *)viewControllers
direction:(UIPageViewControllerNavigationDirection)direction
animated:(BOOL)animated
completion:(void (^)(BOOL finished))completion;`
Це той самий метод, який використовується для налаштування першого контролера перегляду на сторінці. Так само ви можете використовувати його для переходу на інші сторінки.
Цікаво, чому viewControllers
це масив, а не єдиний контролер перегляду?
Це тому, що контролер перегляду сторінок може мати "хребет" (як в 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 тут опущена, вона повинна повернути правильний контролер подання для даного індексу.
- (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];
Я міг би зовсім пропустити щось тут, але це рішення здається набагато простішим, ніж запропоновано багатьма іншими.
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)
}
}
}
}
Цей код добре працював для мене, дякую.
Це те, що я зробив з цим. Деякі способи крокувати вперед або назад і один для прямого переходу на певну сторінку. Документ для 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];
}
}
Швидкий 4:
Мені потрібно було перейти до наступного контролера, коли я натискаю наступний на контролері перегляду сторінок, а також оновлюю індекс pageControl, тому це було найкращим і найпростішим рішенням для мене :
let pageController = self.parent as! PageViewController
pageController.setViewControllers([parentVC.orderedViewControllers[1]], direction: .forward, animated: true, completion: nil)
pageController.pageControl.currentPage = 1
А як щодо використання методів данихSource?
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
}
}
}
Однак, використовуючи цей метод "self.pageViewController setViewControllers", виклик не викликає "viewDidDissapear" на viewController для сторінки, яка була відвернута, тоді як перевернення сторінки вручну робить виклик viewDidDissapear на відхиленій сторінці. Я вважаю, що це причина моєї краху
"Кількість наданих контролерів перегляду (0) не відповідає необхідній кількості (1) для запитуваного переходу"
Також мені потрібна була кнопка для навігації зліва на PageViewController, яка повинна робити саме те, що ви очікуєте від руху пальцем.
Оскільки у мене було створено кілька правил всередині " pageViewController: viewControllerBeforeViewController " для роботи з природною навігаційною швидкістю , я хотів, щоб кнопка повторно використовувала весь цей код, і просто не могла дозволити собі використовувати конкретні індекси щоб дійти до сторінок, як попередні відповіді зробили. Отже, мені довелося приймати альтернативне рішення.
Зауважте, що наступний код призначений для контролера перегляду сторінки, який є властивістю в моєму власному режимі 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];
}
}
Ви можете зробити щось дуже схоже, щоб зробити тут правильну кнопку навігації.
У випадку, якщо 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;
}
}
// Спеціальна логіка кнопки (Попередня та наступна)
-(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];
Я сподіваюся, що це працює :)
На одній сторінці я щойно відредагував відповідь @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];
}
Як вказував @samwize, спосіб пагірування - це використання
setViewControllers:array
Ось як я це зробив: у мене є окремий джерело даних та делегат. Ви можете зателефонувати за цим методом і змінити лише подання "наступний". Попередньо ви повинні застосувати правила підкачки. Тобто ви повинні перевірити напрямок і наступний контролер. Якщо ви використовуєте цей метод зі своїм власним джерелом даних, масив контролерів, що відображається, не зміниться (оскільки ви будете використовувати користувацький масив на підкласі NSObject).
Використовуючи власний джерело даних, метод просто встановлює новий вид (із конкретним напрямком). Оскільки ви все одно будете контролювати сторінки, які відображатимуться під час звичайного перенесення.
Я працюю над ним з вчорашнього дня, і я нарешті зробив це. Я не міг використати стандартний шаблон повністю, тому що у мене є три різні елементи viewControllers як перегляди дітей:
1 - rootViewController;
2 - model;
3 - viewControllers
3.1 - VC1;
3.2 - VC2;
3.3 - VC3.
Note: all of VCs has Storyboard ID.
Мені потрібна була тригерна кнопка лише в першому ВК, тому я додав одну властивість для pageViewController та моделі:
#import <UIKit/UIKit.h>
#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, щоб запустити сторінкуViewController метод setViewControllers: напрям: анімований: завершення ::
- (IBAction)go:(id)sender
{
VC2 *vc2 = [_model.pages objectAtIndex:1];
NSArray *viewControllers = @[vc2];
[_pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
}
Зауважте, що мені не потрібно знаходити індекси ДК, моя кнопка переводить мене до другого ВК, але не важко отримати всі індекси та відслідковувати ваші дитячі уявлення:
- (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];
}
Я сподіваюся, що це допоможе тобі!
Ось рішення з використанням методів UIPageViewControllerDataSource :
Код відстежує поточний відображений контролер перегляду в UIPageViewController .
...
@property (nonatomic, strong) UIViewController *currentViewController;
@property (nonatomic, strong) UIViewController *nextViewController;
...
Спочатку ініціалізуйте currentViewController до початкового контролера перегляду, встановленого для UIPageViewController .
- (void) viewDidLoad {
[super viewDidLoad];
...
self.currentViewController = self.viewControllers[0];
...
[self.pageViewController setViewControllers: @[self.currentViewController] direction: dir animated: YES completion: nil];
}
Потім стежити currentViewController в UIPageViewControllerDelegate методами: pageViewController: willTransitionToViewControllers: і pageViewController: didFinishAnimating: previousViewControllers: transitionCompleted: .
- (nullable UIViewController *) pageViewController: (UIPageViewController *) pageViewController viewControllerBeforeViewController: (UIViewController *) viewController {
NSInteger idx = [self.viewControllers indexOfObject: viewController];
if (idx > 0) {
return self.viewControllers[idx - 1];
} else {
return nil;
}
}
- (nullable UIViewController *) pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController: (UIViewController *) viewController {
NSInteger idx = [self.viewControllers indexOfObject: viewController];
if (idx == NSNotFound) {
return nil;
} else {
if (idx + 1 < self.viewControllers.count) {
return self.viewControllers[idx + 1];
} else {
return nil;
}
}
}
- (void) pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers {
self.nextViewController = [pendingViewControllers firstObject];
}
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray<UIViewController *> *)previousViewControllers transitionCompleted:(BOOL)completed {
if (completed) {
self.currentViewController = self.nextViewController;
}
}
Нарешті, в способі за вашим вибором (в наведеному нижче прикладі це - (IBAction) onNext: (ID) відправника ), ви можете програмно перейти до наступного або попереднього контролера з допомогою UIPageViewControllerDataSouce методів pageViewController: viewControllerBeforeViewController: , pageViewController: viewControllerAfterViewController: щоб отримати наступний чи попередній контролер перегляду та перейдіть до нього, викликаючи [self.pageViewController setViewControllers: @ [vc] напрямок: UIPageViewControllerNavigationDirectionНаперед анімований: YES завершення: nil];
- (void) onNext {
UIViewController *vc = [self pageViewController: self.tutorialViewController viewControllerAfterViewController: self.currentViewController];
if (vc != nil) {
self.currentViewController = vc;
[self.tutorialViewController setViewControllers: @[vc] direction: UIPageViewControllerNavigationDirectionForward animated: YES completion: nil];
}
}
Оскільки ViewControllers вбудовані у PageViewController, все, що вам потрібно зробити:
Приклад в Xamarin, але функціонально схожий на Swift і т.д. Наступний код буде в кнопці Делегат клацання в одному з ViewControllers, який відображається як сторінка:
var parent = ParentViewController as WelcomePageViewController;
var next = parent.DataSource.GetNextViewController(parent, this);
parent.SetViewControllers(new UIViewController[] { next }, UIPageViewControllerNavigationDirection.Forward, true, null);