UIPageViewController: zwraca bieżący widoczny widok

89

Skąd wiesz, jaka jest bieżąca strona / widok wyświetlany w środku UIPageViewController?

Zastąpiłem viewDidAppearmetodę moich widoków podrzędnych, aby wysyłały identyfikator do widoku nadrzędnego w swojej viewDidAppearmetodzie.

Jednak problem jest następujący: nie mogę niezawodnie używać tego identyfikatora jako identyfikatora wyświetlanej strony. ponieważ jeśli użytkownik przewróci stronę, ale w połowie zdecyduje się zatrzymać przewracanie i odłożyć stronę z powrotem, viewDidAppearzostanie już wywołany. (widok jest widoczny za zawiniętą stroną).

Może powinienem przełączyć się na nowy identyfikator tylko wtedy, gdy obecny widok zniknie. Ale zastanawiam się, czy nie ma prostszego sposobu na przywrócenie widoku, który jest obecnie widoczny?

Jan
źródło
Czy próbowałeś viewDidAppear:animated:zamiast tego użyć ?
Do
O tak. Użyłem tego. Zredagowałem pytanie, aby poprawić mój błąd.
stycznia
Sposób, w jaki zredagowałeś pytanie, nie ma dla mnie sensu. Albo wyślesz ten identyfikator z poziomu viewWillAppear lub z viewDidAppear. Sprawdź ponownie swoją zmianę.
Do
Przepraszam, źle wykonałem pracę, edytując pytanie. Cały czas używałem viewDidAppear. Mam nadzieję, że moja ostatnia zmiana to wyjaśnia.
Sty
Spójrzcie tutaj chłopaki, to działa dla mnie stackoverflow.com/a/36860663/4286947
theDC

Odpowiedzi:

103

Należy ręcznie śledzić bieżącą stronę. Metoda delegata pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:powie Ci, kiedy zaktualizować tę zmienną. Ostatni argument metody transitionCompleted:może powiedzieć, czy użytkownik ukończył zmianę strony, czy nie.

Ole Begemann
źródło
1
+1 za poprawną odpowiedź - żałuję, że nie mogłem pracować z UIPageViewController i obsługiwać tylko iOS5.
Do
Dzięki, to jest dokładnie to czyste rozwiązanie, którego szukałem. lepiej niż delegaci na stronach.
stycznia
3
Kiedy obracasz urządzenie, jak możesz śledzić bieżącą stronę?
Satyam
@ Dopóki możesz, po prostu ustaw minimalną wersję swojego projektu na ios5.0
mtmurdock
84
Po czym poznać, czy zwiększyć, czy zmniejszyć bieżący numer strony?
shim
59

Od iOS 6 odkryłem, że viewControllerswłaściwość UIPageViewController jest stale aktualizowana, dzięki czemu zawsze będzie zawierał jeden kontroler widoku, który reprezentuje bieżącą stronę i nic więcej. W ten sposób możesz uzyskać dostęp do bieżącej strony, wywołując viewControllers[0](zakładając, że w danym momencie jest wyświetlany tylko jeden kontroler widoku).

Tablica viewController aktualizuje się tylko wtedy, gdy strona „zablokuje się” na miejscu, więc jeśli użytkownik zdecyduje się częściowo odsłonić następną stronę, nie stanie się ona stroną „bieżącą”, chyba że dokończy przejście.

Jeśli chcesz śledzić „numery stron”, przypisz kontrolerom widoku wartość indeksu podczas ich tworzenia za pomocą metod źródła danych UIPageViewController.


Na przykład:

-(void)autoAdvance
    {
    UIViewController *currentVC = self.viewControllers[0];
    NSUInteger currentIndex = [myViewControllers indexOfObject:currentVC];

    if ( currentIndex >= (myViewControllers.count-1) ) return;

    [self setViewControllers:@[myViewControllers[ currentIndex+1 ]]
        direction:UIPageViewControllerNavigationDirectionForward
        animated:YES
        completion:nil];
    }
-(NSInteger)presentationIndexForPageViewController:
                         (UIPageViewController *)pageViewController
    {
    // return 0;
    UIViewController *currentVC = self.viewControllers[0];
    NSUInteger currentIndex = [myViewControllers indexOfObject:currentVC];
    return currentIndex;
    }

Ale zwróć uwagę na komentarze, że jest to niewiarygodne.

Eddy Borja
źródło
2
Okazało się, że jest to zawodne. Nie mogłem znaleźć źródła problemu. Po zakończeniu animacji uzyskuję dostęp do viewControllerswłaściwości i otrzymuję odpowiednie kontrolery widoku, ale kiedy obracam w metodzie spineLocationForInterfaceOrientation, nie otrzymuję już poprawnych kontrolerów widoku. Dlatego trzymałem się własnej właściwości currentPage zamiast zawsze polegać na viewControllers.
Fábio Oliveira
Ciekawe, pobawię się trochę, aby zobaczyć, jak zachowuje się w tych specjalnych przypadkach
Eddy Borja
2
Okazało się również, że jest to zawodne. Wygląda na to, że Apple po prostu wywołuje viewControllerBeforeViewController lub viewControllerAfterViewController dla każdego obrotu strony, ale nie aktualizuje UIPageViewController.viewControllers. Nie wiem, jak udaje im się przez to źle, ale robią. To naprawdę zwiększa moje obciążenie pracą i łamie przejrzystość mojego kodu (często narusza DRY i inne zasady).
Zack Morris
3
@ZackMorris. To absolutnie niewiarygodne, masz rację. To „moment horroru Apple”. Dlaczego, och, dlaczego nie miałyby zawierać oczywistych funkcji, takich jak przesunięcie jednej w prawo, na której aktualnie jestem stronie, itd. Itd. To niesamowite, że nie możesz „pobrać strony, na której się znajdujesz !!!”.
Fattie
1
Self.viewControllers [0] wydaje mi się działać dobrze. Ale po prostu wywołuję setViewControllers raz podczas inicjacji, a resztę zostawiłem automatyzacji. (testowane w iOS 8.4)
Bob
45

Niestety wszystkie powyższe metody mi nie pomogły. Niemniej jednak znalazłem rozwiązanie za pomocą tagów. Może nie jest to najlepsze, ale działa i mam nadzieję, że komuś pomoże:

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed 
{
    if (completed) {
        int currentIndex = ((UIViewController *)self.pageViewController.viewControllers.firstObject).view.tag;
        self.pageControl.currentPage = currentIndex;
    }
}

In Swift: (dzięki @Jessy )

func pageViewController(pageViewController: UIPageViewController,
    didFinishAnimating finished: Bool,
    previousViewControllers: [UIViewController],
    transitionCompleted completed: Bool)
{
    guard completed else { return }
    self.pageControl.currentPage = pageViewController.viewControllers!.first!.view.tag
}

Przykład: gist

Zwycięzca
źródło
3
Wydaje się to najprostsze i dobrze mi się sprawdziło. Ustawiłem tagi przy dodawaniu kontrolerów widoku (np. HelpPage1ViewController * page1 = [self.storyboard instantiateViewControllerWithIdentifier: @ "page1"]; page1.view.tag = 0;). Następnie możesz ustawić właściwość currentPage dla głównego kontrolera widoku, aby śledzić, gdzie jesteś. Pamiętaj, aby dodać oba protokoły („<UIPageViewControllerDataSource, UIPageViewControllerDelegate>”), a nie tylko źródło danych, i ustawić delegata na self („self.pageViewController.delegate = self;”) lub metoda nie zostanie wywołana. Trochę mnie to zaskoczyło.
James Toomey,
1
@VictorM to rozwiązanie nie działa u mnie. Mam pageViewController z różnymi obrazami. Ciągle zwraca tag 0 po każdym przesunięciu, czy wiesz, dlaczego tak się dzieje? Z góry
dziękuję
1
@VictorM Spędziłem kilka dni próbując zapisać indeks, ale przypadkowo znalazłem tę odpowiedź, chciałbym móc zagłosować 1000 razy, dziękuję!
Evgeniy Kleban
1
Świetne rozwiązanie Dzięki spędzonym godzinami próbując obejść ten problem
Vision Mkhabela
Zwraca tylko wartość 0. Czy robię coś źle
N. Der
35

Opierając się na odpowiedzi Ole…

Oto jak zaimplementowałem 4 metody śledzenia bieżącej strony i aktualizowania wskaźnika strony do prawidłowego indeksu:

- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController{

    return (NSInteger)[self.model count];

}

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController{

    return (NSInteger)self.currentIndex;
}

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers{

    SJJeanViewController* controller = [pendingViewControllers firstObject];
    self.nextIndex = [self indexOfViewController:controller];

}

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{

    if(completed){

        self.currentIndex = self.nextIndex;

    }

    self.nextIndex = 0;

}
Corey Floyd
źródło
2
Myślę, że ostatnia linia powinna być self.nextIndex = self.currentIndexraczej niż self.nextIndex = 0w celu prawidłowego przywrócenia indeksu, gdy przejście nie zostało zakończone. W przeciwnym razie ryzykujesz, że skończysz z currentIndexwartością 0 podczas szybkiego przewijania w przód iw tył gdzieś pośrodku stron.
hverlind
1
To nie działa dla mnie w pełni. Czasami pageViewController: willTransitionToViewControllers nie jest wywoływana, a zatem nextIndex nie jest zmieniany, a bieżący indeks jest wtedy nieprawidłowy.
Hayden Holligan
31

Poniższe rozwiązanie zadziałało dla mnie.

Firma Apple mogłaby uniknąć wielu problemów, zwiększając konfigurowalność natywnej paginacji widoku przewijania UIPageViewController. Musiałem uciekać się do nakładania nowych UIView i UIPageControl tylko dlatego, że natywna paginacja UIPageViewController nie obsługuje przezroczystego tła ani zmiany położenia w ramce widoku.

- (void)pageViewController:(UIPageViewController *)pvc didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
  if (!completed)
  {
    return;
  }
  NSUInteger currentIndex = [[self.pageViewController.viewControllers lastObject] index];
  self.pageControl.currentPage = currentIndex;
}
sirvine
źródło
1
w tym co masz na myśli przez indeks?
Yohan,
Otrzymuję indeks (tj. Liczbę całkowitą, która reprezentuje pozycję bieżącego kontrolera widoku w tablicy self.pageViewController.viewControllers), a następnie używam go do ustawienia atrybutu currentPage self.pageControl (który oczekuje wartości całkowitej) . Ma sens?
sirvine
6
indeks jest tutaj niestandardową własnością, jak sądzę
Adam Johns,
Problem polega na tym, że jeśli chcesz zmienić stronę bez animacji, metoda nie zostanie wywołana
Silviu St
19

Szybki 4

Bez zbędnego kodu. 3 sposoby na zrobienie tego. Korzystanie z metody UIPageViewControllerDelegate .

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    guard completed else { return }

    // using content viewcontroller's index
    guard let index = (pageViewController.viewControllers?.first as? ContentViewController)?.index else { return }

    // using viewcontroller's view tag
    guard let index = pageViewController.viewControllers?.first?.view.tag else { return }

    // switch on viewcontroller
    guard let vc = pageViewController.viewControllers?.first else { return }
    let index: Int
    switch vc {
    case is FirstViewController:
        index = 0
    case is SecondViewController:
        index = 1
    default:
        index = 2
    }
}
Nikola Milicevic
źródło
Dzięki Bogu! Nie wiedziałem o pageViewController.viewControllers. Skąd wiesz, że viewControllers?. To ten, o którym mowa?
Script Kitty
Właściwie dość prosta tablica viewControllers zawiera tylko aktualnie prezentowany kontroler widoku.
Nikola Milicevic
3
jak uzyskać dostęp do zmiennej indeksu z tej funkcji?
N. Der
11

Śledzę indeks strony, używając małej funkcji i określając pageIndex jako statyczny NSInteger.

-(void) setPageIndex
{
    DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0];

    pageIndex = [self.modelController indexOfViewController:theCurrentViewController];
}

i wywołanie [self setPageIndex];wewnątrz funkcji określonej przez Ole, a także po wykryciu zmiany orientacji.

Wahib Ul Haq
źródło
5

Najpierw użyłem rozwiązania Corey, ale nie działało na iOS5, a potem skończyło się na,

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{

    if(completed) {
        _currentViewController = [pageViewController.viewControllers lastObject];
    }
}

Próbował przełączać się między różnymi stronami i na razie działa dobrze.

Basit Ali
źródło
3

Niestety nic powyżej nie działa.

Mam dwa kontrolery widoku i kiedy nieznacznie (około 20px) przewijam ostatni widok do tyłu, uruchamia delegata:

pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

i mówiąc, że bieżąca strona (indeks) to 0 jest nieprawidłowa.

Używanie delegata wewnątrz child viewController coś takiego:

- (void)ViewController:(id)VC didShowWithIndex:(long)page;

// and a property

@property (nonatomic) NSInteger index;

który jest uruchamiany wewnątrz, viewDidAppearjak:

- (void)viewDidAppear:(BOOL)animated
{
    ...

    [self.delegate ViewController:self didShowWithIndex:self.index];
}

Pracował dla mnie.

0yeoj
źródło
3

U mnie to działa niezawodnie

Mam niestandardowy UIPageController. Ta stronaController.currentPage jest aktualizowana na podstawie wyświetlanego elementu UIViewController w pliku viewWillAppear

   var delegate: PageViewControllerUpdateCurrentPageNumberDelegate?

      init(delegate: PageViewControllerUpdateCurrentPageNumberDelegate ){
        self.delegate = delegate
        super.init(nibName: nil, bundle: nil)
      }

      required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }

    override func viewWillAppear(animated: Bool) {

        if delegate != nil {
          self.delegate!.upateCurrentPageNumber(0) //(0) is the pageNumber corresponding to the displayed controller
        }
      } 

    //In the pageViewController 

    protocol PageViewControllerUpdateCurrentPageNumberDelegate {

      func upateCurrentPageNumber(currentPageIndex: Int)
    }

     create the view display controllers initializing with the delegate

    orderedViewControllers = {
              return [
                IntroductionFirstPageViewController(delegate: self),
                IntroductionSecondPageViewController(delegate: self),
                IntroductionThirdPageViewController(delegate: self)
              ]

            }()

    the function implementing the protocol

    func upateCurrentPageNumber(currentPageIndex: Int){
        pageControl.currentPage = currentPageIndex
      }
lguerra10
źródło
1

Używam już view.tagod jakiegoś czasu, próba śledzenia bieżącej strony była zbyt skomplikowana.

W tym kodzie indeks jest przechowywany we tagwłaściwości każdego viewi służy do pobierania następnego lub poprzedniego VC. Za pomocą tej metody można również stworzyć nieskończony zwój. Sprawdź komentarz w kodzie, aby wyświetlić również to rozwiązanie:

extension MyPageViewController: UIPageViewControllerDataSource {

  func viewControllerWithIndex(var index: Int) -> UIViewController! {
    let myViewController = storyboard?.instantiateViewControllerWithIdentifier("MyViewController") as MyViewController

    if let endIndex = records?.endIndex {
      if index < 0 || index >= endIndex { return nil }
      // Instead, We can normalize the index to be cyclical to create infinite scrolling
      // if index < 0 { index += endIndex }
      // index %= endIndex
    }

    myViewController.view.tag = index
    myViewController.record = records?[index]

    return myViewController
  }

  func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
    let index = viewController.view?.tag ?? 0
    return viewControllerWithIndex(index + 1)
  }

  func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
    let index = viewController.view?.tag ?? 0
    return viewControllerWithIndex(index - 1)
  }

  func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
    return records?.count ?? 0
  }

  func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
    return (pageViewController.viewControllers.first as? UIViewController)?.view.tag ?? 0
  }
}
Yariv Nissim
źródło
1

Dziękuję za odpowiedź chłopaki, napotkałem podobny problem, musiałem przechowywać indeks. Lekko modyfikuję kod, wklejam go poniżej:

- (MenuListViewController *)viewControllerAtIndex:(NSInteger)index {

    if (_menues.count < 1)
        return nil;

    //    MenuListViewController *childViewController = [MenuListViewController initWithSecondSetFakeItems];
    MenuListViewController *childViewController = self.menues[index];
    childViewController.index = index;

    return childViewController;
}

#pragma mark - Page View Controller Data Source

- (void)pageViewController:(UIPageViewController *)pageViewController
        didFinishAnimating:(BOOL)finished
   previousViewControllers:(NSArray<UIViewController *> *)previousViewControllers
       transitionCompleted:(BOOL)completed{

    if (completed) {

        NSUInteger currentIndex = ((MenuListViewController *)self.pageController.viewControllers.firstObject).index;
        NSLog(@"index %lu", (unsigned long)currentIndex);
    }
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
    NSUInteger index = [(MenuListViewController *)viewController index];

    if (index == 0)
        return nil;

    index --;

    return [self viewControllerAtIndex:index];
}


- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{

    NSUInteger index = [(MenuListViewController *)viewController index];

    index ++;

    if (index == _menues.count)
        return nil;

    return [self viewControllerAtIndex:index];
}
Evgeniy Kleban
źródło
0
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {

    NSLog(@"Current Page = %@", pageViewController.viewControllers);

    UIViewController *currentView = [pageViewController.viewControllers objectAtIndex:0];

    if ([currentView isKindOfClass:[FirstPageViewController class]]) {
             NSLog(@"First View");
        }
        else if([currentView isKindOfClass:[SecondPageViewController class]]) {
             NSLog(@"Second View");
        }
        else if([currentView isKindOfClass:[ThirdViewController class]]) {
              NSLog(@"Third View");
        }
}

//pageViewController.viewControllers always return current visible View ViewController
avinash
źródło
0

Poniżej kod demonstracyjny (w Swift 2), który demonstruje, jak to się robi, implementując prosty samouczek do przesuwania obrazu. Komentarze w samym kodzie:

import UIKit

/*
VCTutorialImagePage represents one page show inside the UIPageViewController.
You should create this page in your interfacebuilder file:
- create a new view controller
- set its class to VCTutorialImagePage
- sets its storyboard identifier to "VCTutorialImagePage" (needed for the loadView function)
- put an imageView on it and set the contraints (I guess to top/bottom/left/right all to zero from the superview)
- connect it to the "imageView" outlet
*/

class VCTutorialImagePage : UIViewController {
    //image to display, configure this in interface builder
    @IBOutlet weak var imageView: UIImageView!
    //index of this page
    var pageIndex : Int = 0

    //loads a new view via the storyboard identifier
    static func loadView(pageIndex : Int, image : UIImage) -> VCTutorialImagePage {
        let storyboard = UIStoryboard(name: storyBoardHome, bundle: nil)
        let vc = storyboard.instantiateViewControllerWithIdentifier("VCTutorialImagePage") as! VCTutorialImagePage
        vc.imageView.image      = image
        vc.pageIndex            = pageIndex
        return vc
    }
}


/*
VCTutorialImageSwiper takes an array of images (= its model) and displays a UIPageViewController 
where each page is a VCTutorialImagePage that displays an image. It lets you swipe throught the 
images and will do a round-robbin : when you swipe past the last image it will jump back to the 
first one (and the other way arround).

In this process, it keeps track of the current displayed page index
*/

class VCTutorialImageSwiper: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    //our model = images we are showing
    let tutorialImages : [UIImage] = [UIImage(named: "image1")!, UIImage(named: "image2")!,UIImage(named: "image3")!,UIImage(named: "image4")!]
    //page currently being viewed
    private var currentPageIndex : Int = 0 {
        didSet {
            currentPageIndex=cap(currentPageIndex)
        }
    }
    //next page index, temp var for keeping track of the current page
    private var nextPageIndex : Int = 0


    //Mark: - life cylce


    override func viewDidLoad() {
        super.viewDidLoad()
        //setup page vc
        dataSource=self
        delegate=self
        setViewControllers([pageForindex(0)!], direction: .Forward, animated: false, completion: nil)
    }


    //Mark: - helper functions

    func cap(pageIndex : Int) -> Int{
        if pageIndex > (tutorialImages.count - 1) {
            return 0
        }
        if pageIndex < 0 {
            return (tutorialImages.count - 1)
        }
        return pageIndex
    }

    func carrouselJump() {
        currentPageIndex++
        setViewControllers([self.pageForindex(currentPageIndex)!], direction: .Forward, animated: true, completion: nil)
    }

    func pageForindex(pageIndex : Int) -> UIViewController? {
        guard (pageIndex < tutorialImages.count) && (pageIndex>=0) else { return nil }
        return VCTutorialImagePage.loadView(pageIndex, image: tutorialImages[pageIndex])
    }

    func indexForPage(vc : UIViewController) -> Int {
        guard let vc = vc as? VCTutorialImagePage else {
            preconditionFailure("VCPagImageSlidesTutorial page is not a VCTutorialImagePage")
        }
        return vc.pageIndex
    }


    //Mark: - UIPageView delegate/datasource


    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        return pageForindex(cap(indexForPage(viewController)+1))
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        return pageForindex(cap(indexForPage(viewController)-1))
    }

    func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) {
        nextPageIndex = indexForPage(pendingViewControllers.first!)
    }

    func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        if !finished { return }
        currentPageIndex = nextPageIndex
    }

    func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
        return tutorialImages.count
    }

    func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
        return currentPageIndex
    }

}
HixField
źródło
0

Mam tablicę viewControllers , którą wyświetlam w UIPageViewController .

extension MyViewController: UIPageViewControllerDataSource {

func presentationCount(for pageViewController: UIPageViewController) -> Int {
    return self.viewControllers.count
}

func presentationIndex(for pageViewController: UIPageViewController) -> Int {
    return self.currentPageIndex
}
}




extension MyViewController: UIPageViewControllerDelegate {

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {

    if !completed { return }

    guard let viewController = previousViewControllers.last, let index = indexOf(viewController: viewController) else {
        return
    }

    self.currentPageIndex = index

}

fileprivate func indexOf(viewController: UIViewController) -> Int? {
    let index = self.viewControllers.index(of: viewController)
    return index
}
}

Ważną rzeczą jest, aby zauważyć, że setViewControllers metoda UIPageViewController nie daje żadnej zwrotnego delegata. Wywołania zwrotne pełnomocnika reprezentują tylko akcje dotykowe użytkownika w UIPageViewController .

jarora
źródło
0

Oto rozwiązanie, które wymyśliłem:

class DefaultUIPageViewControllerDelegate: NSObject, UIPageViewControllerDelegate {

    // MARK: Public values
    var didTransitionToViewControllerCallback: ((UIViewController) -> Void)?

    // MARK: Private values
    private var viewControllerToTransitionTo: UIViewController!

    // MARK: Methods
    func pageViewController(
        _ pageViewController: UIPageViewController,
        willTransitionTo pendingViewControllers: [UIViewController]
    ) {
        viewControllerToTransitionTo = pendingViewControllers.last!
    }

    func pageViewController(
        _ pageViewController: UIPageViewController,
        didFinishAnimating finished: Bool,
        previousViewControllers: [UIViewController],
        transitionCompleted completed: Bool
    ) {
        didTransitionToViewControllerCallback?(viewControllerToTransitionTo)
    }
}

Stosowanie:

 let pageViewController = UIPageViewController()
 let delegate = DefaultUIPageViewControllerDelegate()

 delegate.didTransitionToViewControllerCallback = {
    pageViewController.title = $0.title
 }

 pageViewController.title = viewControllers.first?.title
 pageViewController.delegate = delegate

Upewnij się, że ustawiłeś tytuł początkowy

Peter Combee
źródło
0

Najprostszym sposobem podejścia do tego IMHO jest użycie PageControl do przechowywania potencjalnego wyniku przejścia, a następnie przywrócenie go, jeśli przejście zostało anulowane. Oznacza to, że kontrolka strony zmienia się, gdy tylko użytkownik zacznie przesuwać, co jest w porządku. Wymaga to posiadania własnej tablicy UIViewControllers (w tym przykładzie o nazwie allViewControllers)

func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
    if let index = self.allViewControllers.index(of: pendingViewControllers[0]) {
        self.pageControl.currentPage = index
    }
}

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    if !completed, let previousIndex = self.allViewControllers.index(of: previousViewControllers[0]) {
        self.pageControl.currentPage = previousIndex
    }
}
Swift Taylor
źródło
0

Co powiesz na zapytanie viewControllerbezpośrednio z UIPageViewController(wersja Swift 4):

fileprivate weak var currentlyPresentedVC: UIViewController?

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    currentlyPresentedVC = pageViewController.viewControllers?.first
}

Lub, jeśli potrzebujesz tylko aktualnie prezentowanego kontrolera widoku w pewnym momencie, po prostu użyj pageViewController.viewControllers?.firstw tym momencie.

Milan Nosáľ
źródło
0

W szybkiej 5 i następującej po sirvine odpowiedzi

extension InnerDetailViewController: UIPageViewControllerDelegate {

    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {

        if completed {
            guard let newIndex = embeddedViewControllers.firstIndex(where: { $0 == pageViewController.viewControllers?.last }) else { return }
            print(newIndex)
            currentEmbeddedViewControllerIndex = newIndex
        }

    }

} 

W tym przypadku nie obchodzi mnie, która klasa UIViewController jest osadzona

Reimond Hill
źródło
-1
UIViewController *viewController = [pageViewController.viewControllers objectAtIndex:0];
NSUInteger currentIndex = [(ViewController*) viewController indexNumber];

Zwróci bieżący indeks strony. i musi używać tego kodu w ramach funkcji delegata UIPageViewController (didFinishAnimating).

Vinay Podili
źródło