Czy możliwe jest programowe przewracanie strony w UIPageViewController?

161

Czy można programowo włączyć stronę UIPageViewController?

RAGOpoR
źródło
1
czy możesz przesłać przykładowy kod. Dziękuję.
iPhone programowo

Odpowiedzi:

235

Tak, jest to możliwe metodą:

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

Jest to ta sama metoda, która jest używana do konfigurowania pierwszego kontrolera widoku na stronie. Podobnie, możesz go użyć, aby przejść do innych stron.

Zastanawiasz się, dlaczego viewControllersto tablica, a nie pojedynczy kontroler widoku?

Dzieje się tak, ponieważ kontroler widoku strony może mieć „kręgosłup” (jak w iBookach), wyświetlający jednocześnie 2 strony treści. Jeśli wyświetlasz 1 stronę treści na raz, po prostu przekaż 1-elementową tablicę.

Przykład w Swift:

pageContainer.setViewControllers([displayThisViewController], direction: .Forward, animated: true, completion: nil)
samwize
źródło
2
Teraz, gdy umowa o zachowaniu poufności dobiegła końca, czy można ją nieco rozszerzyć? Może próbka kodu.
SpaceTrucker
11
Myślę, że w końcu to rozumiem: UIPageViewController nie dba o to, na której stronie jest obecnie. Kiedy wywołujesz setViewControllers, może wydawać się, że w animowany sposób nawigujesz poza bieżącym kontrolerem widoku, ale tak naprawdę nie szuka strony.
Amy,
3
przykład: [self setViewControllers: @ [vcToMoveTo] direction: UIPageViewControllerNavigationDirectionForward animowane: YES ukończenie: nil]; // gdzie vcToMoveTo jest UIViewController
finneycanhelp
1
Jeśli chcesz nadal korzystać UIPageControl, to może warto: self.currentIndex = viewControllerToMoveTo na indeks następnie przez presentationIndexForPageViewController powrotnej self.currentIndex
Brendan
3
Sprawdź stackoverflow.com/questions/22554877/ ... jeśli chcesz również zaktualizować wyświetlacz wskaźnika strony
Protongun.
37

Ponieważ również tego potrzebowałem, omówię bardziej szczegółowo, jak to zrobić.

Uwaga: Zakładam, że użyłeś standardowego formularza szablonu do wygenerowania UIPageViewControllerstruktury - który ma zarówno plik, jak modelViewControlleri dataViewControllerutworzony, gdy go wywołasz. Jeśli nie rozumiesz, co napisałem - wróć i utwórz nowy projekt, który używa rozszerzeniaUIPageViewController będzie podstawą. Wtedy zrozumiesz.

Dlatego przejście do konkretnej strony wymaga skonfigurowania różnych elementów metody wymienionej powyżej. W tym ćwiczeniu przyjmuję, że jest to widok poziomy z dwoma widokami. Zaimplementowałem to również jako IBAction, aby można było to zrobić za pomocą naciśnięcia przycisku lub czegokolwiek - równie łatwo jest wywołać selektor i przekazać potrzebne elementy.

Tak więc w tym przykładzie potrzebujesz dwóch kontrolerów widoku, które zostaną wyświetlone - i opcjonalnie, niezależnie od tego, czy idziesz do przodu w książce, czy do tyłu.

Zwróć uwagę, że po prostu zakodowałem na stałe, gdzie przejść do stron 4 i 5 i używam przesunięcia w przód. Stąd widać, że wszystko, co musisz zrobić, to przekazać zmienne, które pomogą ci zdobyć te przedmioty ...

-(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!  

}
Joe
źródło
2
Mam te same wymagania, aby przejść do określonej strony. Ale powyższy kod wydaje mi się nie działać. Co ja robię źle? Mam 19 stron.
GaneshT
Czy możemy użyć tego fragmentu kodu również przy udostępnianiu kontrolerów widoku za pośrednictwem obiektu źródła danych?
Jens Kohl
20
Co za dziwacznie słabo zaimplementowana klasa, Apple.
devios1
29

Oto inny przykład kodu dla widoku pojedynczej strony. Implementacja dla viewControllerAtIndex została tutaj pominięta, powinna zwrócić prawidłowy kontroler widoku dla danego indeksu.

- (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];
}

Strony można zmieniać, dzwoniąc

[self changePage:UIPageViewControllerNavigationDirectionReverse];
[self changePage:UIPageViewControllerNavigationDirectionForward];
lekksi
źródło
Ale kontrolka indeksu strony nie jest aktualizowana. W jaki sposób mogę to zrobić?
thatzprem
1
Ta odpowiedź działa dla mnie - zauważ jednak, że jeśli polegasz na metodach delegata UIPageViewController „didFinishAnimating”, nie zostaną one uruchomione. Zamiast tego przenieś kod z didFinishAnimating do oddzielnej metody i wywołaj tę metodę z bloku uzupełniania w metodzie setViewControllers.
DiscDev
1
@thatzprem Jeśli chcesz nadal korzystać UIPageControl, to może warto: self.currentIndex = viewControllerToMoveTo za wskaźnik następnie do presentationIndexForPageViewController powrotnej self.currentIndex
Brendan
@thatzprem ma rację. Za każdym razem będzie to ta sama strona, na przykład jeśli mamy 3 strony, to za każdym razem będzie to tylko druga strona.
Tushar Lathiya
18

Mogę czegoś tutaj całkowicie brakować, ale to rozwiązanie wydaje się o wiele prostsze niż wiele innych proponowanych.

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)
            }
        }
    }
}
wfbarksdale
źródło
1
Działa świetnie! Trzeba tylko jakoś zmienić wskaźnik strony.
TruMan1
Naprawdę pomocny! Podaj nam również funkcję goToFirstPage.
Mamta
Za każdym razem będzie to ta sama strona, na przykład jeśli mamy 3 strony, to za każdym razem będzie to tylko druga strona.
Tushar Lathiya
15

Ten kod dobrze mi działał, dzięki.

Oto, co z nim zrobiłem. Niektóre metody przechodzenia do przodu lub do tyłu i jedna do przechodzenia bezpośrednio do określonej strony. Jest to 6-stronicowy dokument w widoku pionowym. Będzie działać dobrze, jeśli wkleisz go do implementacji RootController szablonu 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];

    }

}
Graham
źródło
Chcę go używać w trybie poziomym, w którym istnieją dwie strony. jak go tam używać. czy możesz poprowadzić.
iPhone programowo
9

Swift 4:

Musiałem przejść do następnego kontrolera, gdy dotknę dalej kontrolera widoku kontrolera stron, a także zaktualizowałem indeks pageControl, więc było to dla mnie najlepsze i najprostsze rozwiązanie :

let pageController = self.parent as! PageViewController

pageController.setViewControllers([parentVC.orderedViewControllers[1]], direction: .forward, animated: true, completion: nil)

pageController.pageControl.currentPage = 1
Sam Bing
źródło
5

A co z używaniem metod z dataSource?

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

Analogicznie do tyłu.

JakubKnejzlik
źródło
3

W 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
        }
    }

}
King-Wizard
źródło
1
Czy mógłbyś podać mi na to pełny przykład. Ponieważ robię coś takiego. Jak używać tego rozszerzenia z moim kodem. Jeśli chcesz, mogę wysłać Ci kod.
Saty
2

Jednak użycie tego wywołania metody „self.pageViewController setViewControllers” nie powoduje wywołania „viewDidDissapear” w kontrolerze viewController dla strony, która została odrzucona, podczas gdy ręczne obrócenie strony powoduje wywołanie viewDidDissapear na odwróconej stronie. Myślę, że to jest przyczyną mojej katastrofy

„Liczba dostarczonych kontrolerów widoku (0) nie jest zgodna z liczbą wymaganą (1) dla żądanego przejścia”

noRema
źródło
spróbuj użyć: - pageViewController: didFinishAnimating: previousViewControllers: transakcjaCompleted:
Graham
2

Potrzebowałem również przycisku do nawigacji w lewo na kontrolerze PageViewController, który powinien robić dokładnie to, czego można oczekiwać od ruchu przeciągnięcia.

Ponieważ miałem już kilka reguł w " pageViewController: viewControllerBeforeViewController " do obsługi naturalnej nawigacji po przesunięciu, chciałem, aby przycisk ponownie wykorzystał cały ten kod i po prostu nie mogłem sobie pozwolić na użycie określonych indeksów aby dotrzeć do stron, jak poprzednio odpowiedzi tak. Musiałem więc wybrać alternatywne rozwiązanie.

Należy pamiętać, że poniższy kod dotyczy kontrolera widoku strony, który jest właściwością wewnątrz mojego niestandardowego kontrolera ViewController i ma kręgosłup ustawiony na środek.

Oto kod, który napisałem dla mojego przycisku Nawiguj w lewo:

- (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];
    }
}

Możesz zrobić coś bardzo podobnego, aby utworzyć właściwy przycisk nawigacyjny z tego miejsca.

tuliomir
źródło
2

W przypadku, gdy KONTROLA STRONY wskazująca bieżącą stronę jest O && Chcesz, aby strony nawigowały za pomocą funkcji przewijania, a także poprzez klikanie niestandardowych przycisków w Kontrolerze widoku strony, poniższe mogą być pomocne.

//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];        
}

// Deleguj o nazwie viewControllerAfterViewController, gdy użytkownik przewinie do następnej strony

- (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;
}

}

// Logika przycisków niestandardowych (Wstecz i dalej)

-(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;}
Yogesh Lolusare
źródło
Opublikowałeś prawie taką samą odpowiedź na cztery pytania. Jeśli uważasz, że jeden z nich jest duplikatem drugiego, oznacz je jako takie (i nie publikuj tej samej odpowiedzi kilka razy).
Jaap
Czy mogę więc zamieścić link do tego pytania nad innym podobnym pytaniem, ale rozwiązanie jest takie samo.
Yogesh Lolusare
1
Nie mam zamiaru oceniać ani nic, ale formatowanie twojego kodu wygląda dla mnie bardzo odpychająco.
Lukas Petr
1
Racja @Lukas, sformatuję to teraz. Dzięki
Yogesh Lolusare
2
- (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];

}

// teraz wywołaj tę metodę

[self moveToPage];

Mam nadzieję, że zadziała :)

D.Garcia
źródło
1

W przypadku pojedynczej strony właśnie zredagowałem odpowiedź @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];
}
Smit Shah
źródło
0

Jak zauważył @samwize, sposób paginacji polega na użyciu

setViewControllers:array

Oto sposób, w jaki to zrobiłem: moje źródło danych i delegat są oddzielne. Możesz wywołać tę metodę i zmienić tylko „następny” widok. Wcześniej musisz zastosować reguły stronicowania. Oznacza to, że musisz sprawdzić kierunek i następny kontroler. Jeśli użyjesz tej metody z niestandardowym źródłem danych, tablica kontrolerów, które wyświetlasz, nie ulegnie zmianie (ponieważ użyjesz niestandardowej tablicy w podklasie NSObject).

Korzystając z własnego źródła danych, metoda po prostu ustawia nowy widok (z określonym kierunkiem). Ponieważ nadal będziesz kontrolować strony, które będą wyświetlane podczas normalnego przesuwania.

wolffan
źródło
0

Pracuję nad tym od wczoraj iw końcu to zadziałało. Nie mogłem całkowicie użyć standardowego szablonu, ponieważ mam trzy różne viewControllers jako childviews:

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

Potrzebowałem przycisku wyzwalacza tylko w pierwszym VC, więc dodałem jedną właściwość dla pageViewController i modelu:

#import <UIKit/UIKit.h>
#import "Model.h"

@interface VC1 : UIViewController

@property (nonatomic, strong) UIPageViewController *thePageViewController;
@property (nonatomic, strong) SeuTimePagesModel *theModel;

@end

Przepisałem metodę init modelu, aby przekazać storyboard i pageViewController jako parametry, więc mogłem ustawić je na mój 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;
}

Na koniec dodałem IBAction w moim vc1, aby wyzwolić metodę pageViewController setViewControllers: direction: animated: Complete ::

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

Uwaga Nie muszę wyszukiwać indeksów VC, mój przycisk przenosi mnie do mojego drugiego VC, ale nie jest trudno uzyskać wszystkie indeksy i śledzić swoje widoki dzieci:

- (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];
}

Mam nadzieję, że Ci to pomoże!

Thomás Calmon
źródło
0

Oto rozwiązanie wykorzystujące metody UIPageViewControllerDataSource :

Kod śledzi bieżący wyświetlany kontroler widoku w UIPageViewController .

...
@property (nonatomic, strong) UIViewController *currentViewController;
@property (nonatomic, strong) UIViewController *nextViewController;
...

Najpierw zainicjuj currentViewController do początkowego kontrolera widoku ustawionego dla UIPageViewController .

- (void) viewDidLoad {
    [super viewDidLoad];
    ...
    self.currentViewController = self.viewControllers[0];
    ...
    [self.pageViewController setViewControllers: @[self.currentViewController] direction: dir animated: YES completion: nil];
}

Następnie śledzić currentViewController w UIPageViewControllerDelegate metod: pageViewController: willTransitionToViewControllers: a 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;
    }
}

Na koniec, w sposobie wyboru (w poniższym przykładzie jest to - (IBAction) onNext: (ID) nadawcy ), można programowo przejść do następnego lub poprzedniego kontrolera używając UIPageViewControllerDataSouce metod pageViewController: viewControllerBeforeViewController: , pageViewController: viewControllerAfterViewController: aby uzyskać następny lub poprzedni kontroler widoku i przejdź do niego, wywołując [self.pageViewController setViewControllers: @ [vc] direction: UIPageViewControllerNavigationDirectionForward animowane: YES ukończenie: 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];
    }
}
pconor
źródło
Szczegółowe wyjaśnienie byłoby bardzo przydatne.
Taslim Oseni
@TaslimOseni dzięki za wskazanie, że przykład nie był wystarczająco jasny. Dodałem opis, jak to działa, daj mi znać, jeśli wymaga więcej wyjaśnień.
pconor
0

Ponieważ ViewControllers są osadzone w PageViewController, wszystko, co musisz zrobić, to:

  • Pobierz nadrzędny kontroler widoku i prześlij jako odpowiednią klasę.
  • Użyj tej właściwości źródła danych nadrzędnych, aby uzyskać następny ViewController.
  • Użyj metody SetParentViewControllers, aby ustawić i przejść do następnej strony.

Przykład w Xamarin, ale funkcjonalnie podobny do Swift itp. Poniższy kod byłby w delegacie Button Click w jednym z ViewControllers wyświetlanych jako strona:

var parent = ParentViewController as WelcomePageViewController;
var next = parent.DataSource.GetNextViewController(parent, this);

parent.SetViewControllers(new UIViewController[] { next }, UIPageViewControllerNavigationDirection.Forward, true, null);
Grant K
źródło