Risposte:
Sì, è possibile con il metodo:
- (void)setViewControllers:(NSArray *)viewControllers
direction:(UIPageViewControllerNavigationDirection)direction
animated:(BOOL)animated
completion:(void (^)(BOOL finished))completion;`
Questo è lo stesso metodo utilizzato per impostare il controller della prima vista sulla pagina. Simile, puoi usarlo per andare ad altre pagine.
Ti chiedi perché viewControllers
è un array e non un controller a vista singola?
Questo perché un controller di visualizzazione di pagina potrebbe avere un "dorso" (come in iBooks), che visualizza 2 pagine di contenuto alla volta. Se visualizzi 1 pagina di contenuto alla volta, passa semplicemente in un array di 1 elemento.
Un esempio in Swift:
pageContainer.setViewControllers([displayThisViewController], direction: .Forward, animated: true, completion: nil)
Dal momento che avevo bisogno anche di questo, andrò più in dettaglio su come farlo.
Nota: suppongo che tu abbia usato il modulo modello standard per generare la tua UIPageViewController
struttura - che ha sia il modelViewController
che il dataViewController
creato quando lo invochi. Se non capisci cosa ho scritto, torna indietro e crea un nuovo progetto che usa UIPageViewController
come base. Capirai allora.
Quindi, la necessità di passare a una determinata pagina implica l'impostazione dei vari pezzi del metodo sopra elencato. Per questo esercizio, suppongo che sia una vista orizzontale con due viste che mostrano. Inoltre, l'ho implementato come IBAction in modo che potesse essere fatto premendo un pulsante o cosa no - è altrettanto facile farlo chiamare selettore e passare gli elementi necessari.
Pertanto, per questo esempio sono necessari i due controller di visualizzazione che verranno visualizzati e, facoltativamente, se si procede in avanti nel libro o all'indietro.
Nota che ho semplicemente programmato dove andare alle pagine 4 e 5 e usare una scheda di sicurezza. Da qui puoi vedere che tutto ciò che devi fare è passare le variabili che ti aiuteranno a ottenere questi elementi ...
-(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!
}
Ecco un altro esempio di codice per una singola vista paginata. L'implementazione per viewControllerAtIndex è omessa qui, dovrebbe restituire il controller di visualizzazione corretto per l'indice dato.
- (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];
}
Le pagine possono essere modificate chiamando
[self changePage:UIPageViewControllerNavigationDirectionReverse];
[self changePage:UIPageViewControllerNavigationDirectionForward];
Potrei davvero mancare qualcosa qui, ma questa soluzione sembra molto più semplice di quanto molti altri abbiano proposto.
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)
}
}
}
}
Questo codice ha funzionato bene per me, grazie.
Questo è quello che ho fatto con esso. Alcuni metodi per andare avanti o indietro e uno per andare direttamente a una determinata pagina. È per un documento di 6 pagine in vista verticale. Funzionerà bene se lo incolli nell'implementazione del RootController del modello 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];
}
}
Swift 4:
Avevo bisogno di andare al controller successivo quando toccavo il successivo su un controller di visualizzazione pagecontroller e anche aggiornare l'indice pageControl, quindi questa è stata la soluzione migliore e più semplice per me :
let pageController = self.parent as! PageViewController
pageController.setViewControllers([parentVC.orderedViewControllers[1]], direction: .forward, animated: true, completion: nil)
pageController.pageControl.currentPage = 1
Che dire dell'utilizzo dei metodi da dataSource?
UIViewController *controller = [pageViewController.dataSource pageViewController:self.pageViewController viewControllerAfterViewController:pageViewController.viewControllers.firstObject];
[pageViewController setViewControllers:@[controller] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
Analogamente per tornare indietro.
In Swift :
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
}
}
}
Tuttavia, usando questa chiamata al metodo 'self.pageViewController setViewControllers' non si chiama 'viewDidDissapear' sul viewController per la pagina che è stata girata, mentre girando manualmente una pagina si chiama viewDidDissapear sulla pagina girata. Credo che questa sia la causa del mio incidente
"Il numero di controller di visualizzazione forniti (0) non corrisponde al numero richiesto (1) per la transizione richiesta"
Avevo anche bisogno di un pulsante per navigare a sinistra su PageViewController, uno che dovrebbe fare esattamente quello che ti aspetteresti dal movimento del colpo.
Dato che avevo già adottato alcune regole all'interno di " pageViewController: viewControllerBeforeViewController " per gestire la navigazione a scorrimento naturale, volevo che il pulsante riutilizzasse tutto quel codice e semplicemente non potevo permettermi di utilizzare indici specifici per raggiungere le pagine come le precedenti le risposte hanno fatto. Quindi, ho dovuto prendere una soluzione alternativa.
Si noti che il codice seguente è per un Page View Controller che è una proprietà all'interno del mio ViewController personalizzato e che ha il dorso impostato a metà.
Ecco il codice che ho scritto per il mio pulsante Naviga a sinistra:
- (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];
}
}
Puoi fare qualcosa di molto simile per creare un pulsante di navigazione corretto da qui.
Nel caso in cui CONTROLLO PAGINA per indicare la pagina corrente sia O && Si desidera che le pagine navighino tramite scorrimento e anche facendo clic sui pulsanti personalizzati in Page ViewController, di seguito potrebbe essere utile.
//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];
}
// Delegato chiamato viewControllerAfterViewController quando Utente Scorrere alla pagina successiva
- (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;
}
}
// Logica dei pulsanti personalizzati (precedente e successiva)
-(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];
}
// ora chiama questo metodo
[self moveToPage];
Spero che funzioni :)
Per singola pagina, ho appena modificato la risposta di @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];
}
Come ha sottolineato @samwize, il modo di impaginare è usando
setViewControllers:array
Ecco come l'ho fatto: ho separato l'origine dati e il delegato. È possibile chiamare questo metodo e modificare solo la vista "successiva". In precedenza è necessario applicare le regole di paging. Cioè, devi controllare la direzione e il controller successivo. Se usi questo metodo con l'origine dati personalizzata, l'array di controller che stai visualizzando non cambierà (poiché utilizzerai un array personalizzato su una sottoclasse NSObject).
Utilizzando la propria fonte di dati il metodo imposta semplicemente una nuova vista (con direzione specifica). Dal momento che continuerai a controllare le pagine che verranno visualizzate durante lo scorrimento normale.
Ci sto lavorando da ieri e alla fine l'ho fatto funzionare. Non ho potuto utilizzare totalmente il modello standard, perché ho tre differenti viewController come visualizzazioni figlio:
1 - rootViewController;
2 - model;
3 - viewControllers
3.1 - VC1;
3.2 - VC2;
3.3 - VC3.
Note: all of VCs has Storyboard ID.
Avevo bisogno di un pulsante di attivazione solo nel primo VC, quindi ho aggiunto una proprietà per pageViewController e il modello:
#import <UIKit/UIKit.h>
#import "Model.h"
@interface VC1 : UIViewController
@property (nonatomic, strong) UIPageViewController *thePageViewController;
@property (nonatomic, strong) SeuTimePagesModel *theModel;
@end
Ho riscritto il metodo init del modello per passare storyboard e pageViewController come parametri, in modo da poterli impostare sul mio 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;
}
Infine, ho aggiunto un IBAction nel mio vc1 per attivare il metodo pageViewController setViewController: direction: animato: completamento ::
- (IBAction)go:(id)sender
{
VC2 *vc2 = [_model.pages objectAtIndex:1];
NSArray *viewControllers = @[vc2];
[_pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
}
Nota Non ho bisogno di trovare gli indici VC, il mio pulsante mi porta al mio secondo VC, ma non è difficile ottenere tutti gli indici e tenere traccia delle visualizzazioni dei bambini:
- (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];
}
Spero che ti aiuti!
Ecco una soluzione che utilizza i metodi UIPageViewControllerDataSource :
Il codice tiene traccia dell'attuale controller di visualizzazione visualizzato in UIPageViewController .
...
@property (nonatomic, strong) UIViewController *currentViewController;
@property (nonatomic, strong) UIViewController *nextViewController;
...
Inizializzare innanzitutto currentViewController sul set di controller della vista iniziale per UIPageViewController .
- (void) viewDidLoad {
[super viewDidLoad];
...
self.currentViewController = self.viewControllers[0];
...
[self.pageViewController setViewControllers: @[self.currentViewController] direction: dir animated: YES completion: nil];
}
Poi tenere traccia delle currentViewController nei UIPageViewControllerDelegate metodi: pageViewController: willTransitionToViewControllers: e 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;
}
}
Infine, nel metodo di vostra scelta (nell'esempio qui sotto è di - (IBAction) onNext: (id) del mittente ), di programmazione è possibile passare al controllo successivo o precedente utilizzando UIPageViewControllerDataSouce metodi pageViewController: viewControllerBeforeViewController: , pageViewController: viewControllerAfterViewController: per ottenere il controller della vista precedente o successivo e accedervi chiamando [self.pageViewController setViewControllers: @ [vc] direzione: UIPageViewControllerNavigationDirectionForward animato: SÌ completamento: zero];
- (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];
}
}
Poiché i ViewController sono integrati nel PageViewController, tutto ciò che devi fare è:
Esempio in Xamarin, ma funzionalmente simile a Swift ecc. Il seguente codice sarebbe in Button Click delegate in uno dei ViewController mostrato in una pagina:
var parent = ParentViewController as WelcomePageViewController;
var next = parent.DataSource.GetNextViewController(parent, this);
parent.SetViewControllers(new UIViewController[] { next }, UIPageViewControllerNavigationDirection.Forward, true, null);