UIPageViewController: Gibt die aktuell sichtbare Ansicht zurück


90

Woher wissen Sie, welche aktuelle Seite / Ansicht in einem angezeigt wird UIPageViewController?

Ich habe die viewDidAppearMethode meiner untergeordneten Ansichten überschrieben , sodass sie in ihrer viewDidAppearMethode eine ID an die übergeordnete Ansicht senden .

Das Problem ist jedoch folgendes: Ich kann diese ID nicht zuverlässig als ID für die angezeigte Seite verwenden. Denn wenn der Benutzer die Seite umblättert, aber nach der Hälfte der Zeit beschließt, das Umblättern zu stoppen und die Seite zurückzusetzen, wurde viewDidAppeardies bereits aufgerufen. (Die Ansicht ist hinter der gekräuselten Seite sichtbar).

Vielleicht sollte ich nur zu einer neuen ID wechseln, wenn die aktuelle Ansicht verschwindet. Aber ich frage mich, ob es keinen einfacheren Weg gibt, die aktuell sichtbare Ansicht zurückzugeben.


Haben Sie versucht, viewDidAppear:animated:stattdessen zu verwenden?
Bis zum

Oh ja. Ich habe das benutzt. Ich habe die Frage bearbeitet, um meinen Fehler zu korrigieren.
Januar

Die Art und Weise, wie Sie die Frage bearbeitet haben, macht für mich keinen Sinn. Entweder senden Sie diese ID aus viewWillAppear oder aus viewDidAppear. Bitte überprüfen Sie Ihre Bearbeitung erneut.
Bis zum

Entschuldigung, ich habe die Frage schlecht bearbeitet. Ich habe die ganze Zeit viewDidAppear verwendet. Ich hoffe, meine letzte Änderung verdeutlicht das.
Januar

Antworten:


103

Sie sollten die aktuelle Seite manuell verfolgen. Die Delegate-Methode pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:teilt Ihnen mit, wann diese Variable aktualisiert werden muss. Das letzte Argument der Methode transitionCompleted:kann Ihnen sagen, ob ein Benutzer einen Seitenwechsel abgeschlossen hat oder nicht.


1
+1 für die richtige Antwort - Ich wünschte, ich hätte die Möglichkeit, mit UIPageViewController zu arbeiten und nur iOS5 zu unterstützen.
Bis zum

Danke, das ist genau die saubere Lösung, nach der ich gesucht habe. besser als Delegierte auf den Seiten.
Januar

3
Wie verfolgen Sie die aktuelle Seite, wenn Sie das Gerät drehen?
Satyam

@ Bis Sie können, setzen Sie einfach die Mindestversion Ihres Projekts auf ios5.0
mtmurdock

82
Wie können Sie feststellen, ob die aktuelle Seitenzahl erhöht oder verringert werden soll?
Shim

59

Ab iOS 6 habe ich festgestellt, dass die viewControllersEigenschaft von UIPageViewController ständig aktualisiert wird, sodass immer der eine Ansichtscontroller enthalten ist, der die aktuelle Seite darstellt, und sonst nichts. Auf diese Weise können Sie auf die aktuelle Seite zugreifen, indem Sie anrufen viewControllers[0](vorausgesetzt, Sie zeigen jeweils nur einen Ansichts-Controller an).

Das viewController-Array wird erst aktualisiert, wenn die Seite "eingerastet" ist. Wenn ein Benutzer die nächste Seite teilweise anzeigt, wird sie erst dann zur "aktuellen" Seite, wenn er den Übergang abgeschlossen hat.

Wenn Sie die "Seitenzahlen" verfolgen möchten, weisen Sie Ihren Ansichtscontrollern einen Indexwert zu, wenn Sie sie über die UIPageViewController-Datenquellenmethoden erstellen.


Also zum Beispiel:

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

Aber beachten Sie die Kommentare , dass diese unzuverlässig ist.


2
Ich fand es unzuverlässig. Ich konnte die Ursache des Problems nicht finden. Wenn die Animation beendet ist, greife ich auf die viewControllersEigenschaft zu und erhalte die richtigen Ansichts-Controller. Wenn ich jedoch die Methode drehe, spineLocationForInterfaceOrientationerhalte ich nicht mehr die richtigen Ansichts-Controller. Also habe ich mich daran gehalten, meine eigene currentPage-Eigenschaft beizubehalten, anstatt mich immer auf die zu verlassen viewControllers.
Fábio Oliveira

Interessant, ich werde ein bisschen damit spielen, um zu sehen, wie es sich in diesen besonderen Fällen verhält
Eddy Borja

2
Ich fand es auch unzuverlässig. Es scheint, dass Apple nur viewControllerBeforeViewController oder viewControllerAfterViewController für jeden Seitenwechsel aufruft, UIPageViewController.viewControllers jedoch nicht aktualisiert. Ich weiß nicht, wie sie es immer wieder schaffen, solche Dinge falsch zu machen, aber sie tun es. Dies erhöht meine Arbeitsbelastung erheblich und beeinträchtigt die Klarheit meines Codes (was häufig gegen DRY und andere Prinzipien verstößt).
Zack Morris

3
@ZackMorris. Es ist absolut unglaublich, du hast ganz recht. Es ist ein "Apple Horror Moment". Warum, warum sollten sie nicht die offensichtlichen Funktionen enthalten, wie eine nach rechts verschieben, auf welcher Seite ich mich gerade befinde usw. usw. Es ist ziemlich unglaublich, dass Sie nicht "die Seite bekommen können, auf der Sie sich befinden !!!"
Fattie

1
self.viewControllers [0] scheint für mich gut zu funktionieren. Aber ich rufe setViewControllers während der Initiierung nur einmal auf und überlasse den Rest der Automatisierung. (getestet in iOS 8.4)
Bob

45

Leider haben mir alle oben genannten Methoden nicht geholfen. Trotzdem habe ich die Lösung mithilfe von Tags gefunden. Vielleicht ist es nicht das Beste, aber es funktioniert und ich hoffe, es hilft jemandem:

- (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: (danke an @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
}

Beispiel: Kern


3
Dies scheint am einfachsten zu sein und hat für mich gut funktioniert. Ich habe die Tags beim Hinzufügen der View-Controller festgelegt (z. B. HelpPage1ViewController * page1 = [self.storyboard instantiateViewControllerWithIdentifier: @ "page1"]; page1.view.tag = 0;). Anschließend können Sie eine currentPage-Eigenschaft für den Master-Viewcontroller festlegen, um zu verfolgen, wo Sie sich befinden. Stellen Sie sicher, dass Sie beide Protokolle ("<UIPageViewControllerDataSource, UIPageViewControllerDelegate>") und nicht nur die Datenquelle hinzufügen und den Delegaten auf self ("self.pageViewController.delegate = self;") setzen, da sonst die Methode nicht aufgerufen wird. Das hat mich ein bisschen verblüfft.
James Toomey

1
@ VictorM diese Lösung funktioniert bei mir nicht. Ich habe einen pageViewController mit verschiedenen Bildern. Es wird immer wieder Tag 0 für jeden Schlag zurückgegeben. Gibt es eine Idee, warum dies passiert? Vielen Dank im Voraus
theDC

1
@ VictorM Ich habe mehrere Tage damit verbracht, den Index zu speichern, aber versehentlich diese Antwort gefunden. Ich wünschte, ich könnte 1000-mal upvoten, danke!
Evgeniy Kleban

1
Tolle Lösung Vielen Dank, dass Sie stundenlang versucht haben, dies zu
umgehen

Es gibt nur einen Wert von 0 zurück. Mache ich etwas falsch
N. Der

35

Aufbauend auf Oles Antwort…

So habe ich die 4 Methoden implementiert, um die aktuelle Seite zu verfolgen und den Seitenindikator auf den richtigen Index zu aktualisieren:

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

}

2
Ich denke, die letzte Zeile sollte self.nextIndex = self.currentIndexeher sein als self.nextIndex = 0, um den Index richtig wiederherzustellen, wenn ein Übergang nicht abgeschlossen ist. Andernfalls besteht die Gefahr, dass Sie den currentIndexWert 0 erhalten, wenn Sie irgendwo in der Mitte Ihrer Seiten schnell hin und her blättern.
Hverlind

1
Das funktioniert bei mir nicht ganz. Manchmal wird pageViewController: willTransitionToViewControllers nicht aufgerufen und daher wird nextIndex nicht geändert, und der aktuelle Index ist dann falsch.
Hayden Holligan

31

Die folgende Lösung hat bei mir funktioniert.

Apple könnte viel Ärger vermeiden, indem die native UIPageViewController-Paginierung der Bildlaufansicht konfigurierbarer gemacht wird. Ich musste auf das Überlagern eines neuen UIView und UIPageControl zurückgreifen, nur weil die native UIPageViewController-Paginierung keinen transparenten Hintergrund oder keine Neupositionierung innerhalb des Ansichtsrahmens unterstützt.

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

1
was meinst du damit mit index?
Yohan

Ich erhalte den Index (dh die Ganzzahl, die die Position des aktuellen Ansichtscontrollers im Array von self.pageViewController.viewControllers darstellt) und verwende diesen, um das currentPage-Attribut von self.pageControl festzulegen (das einen ganzzahligen Wert erwartet). . Sinn ergeben?
Sirvine

6
Index ist eine benutzerdefinierte Eigenschaft hier, glaube ich
Adam Johns

Problem dabei ist, dass, wenn Sie Seite ohne Animationsmethode ändern möchten, nicht aufgerufen wird
Silviu St

19

Swift 4

Kein unnötiger Code. 3 Möglichkeiten es zu tun. Verwenden der UIPageViewControllerDelegate- Methode.

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

Danke Gott! Ich wusste es nicht pageViewController.viewControllers. Woher kennen Sie viewController? .Erste ist die fragliche?
Script Kitty

Das Array viewControllers ist eigentlich recht einfach und enthält nur den aktuell dargestellten View Controller.
Nikola Milicevic

2
Wie greife ich über diese Funktion auf die Indexvariable zu?
N. Der

11

Ich verfolge den Seitenindex, indem ich eine kleine Funktion verwende und pageIndex als statische NSInteger spezifiziere.

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

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

und Aufrufen [self setPageIndex];innerhalb der von Ole angegebenen Funktion und auch nach Erkennen der Änderung der Ausrichtung.


5

Ich habe zuerst die Corey-Lösung verwendet, aber sie funktionierte nicht unter iOS5.

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

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

Es wurde versucht, durch verschiedene Seiten zu blättern, und es funktioniert vorerst gut.


3

Leider funktioniert nichts oben für mich.

Ich habe zwei Ansichts-Controller und wenn ich die letzte Ansicht leicht (ca. 20 Pixel) rückwärts scrolle, wird der Delegat ausgelöst:

pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

und zu sagen, dass die aktuelle Seite (Index) 0falsch ist.

Verwenden von delegate in child viewController wie folgt:

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

// and a property

@property (nonatomic) NSInteger index;

das wird im Inneren ausgelöst viewDidAppearwie:

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

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

Hat für mich gearbeitet.


3

Das funktioniert bei mir zuverlässig

Ich habe einen benutzerdefinierten UIPageController. Diese pageController.currentPage wird vom angezeigten UIViewController in der viewWillAppear aktualisiert

   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
      }

1

Ich benutze es schon view.tageine Weile und es war zu kompliziert, den Überblick über die aktuelle Seite zu behalten.

In diesem Code wird der Index im gespeichert tag Eigenschaft von jedemview und zum Abrufen der nächsten oder vorherigen VC verwendet. Mit dieser Methode ist es auch möglich, eine unendliche Schriftrolle zu erstellen. Schauen Sie sich den Kommentar im Code an, um auch diese Lösung anzuzeigen:

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

1

Vielen Dank für Ihre Antwort Jungs, ich hatte ein ähnliches Problem, musste Index speichern. Ich ändere meinen Code leicht und füge ihn unten ein:

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

1

Wie wäre es, wenn Sie viewControllerdirekt bei der UIPageViewController(Swift 4-Version) nach einem fragen :

fileprivate weak var currentlyPresentedVC: UIViewController?

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

Wenn Sie zu einem bestimmten Zeitpunkt nur den aktuell angezeigten Ansichts-Controller benötigen, verwenden Sie ihn einfach pageViewController.viewControllers?.firstzu diesem Zeitpunkt.


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

0

Der folgende Demo-Code (in Swift 2) zeigt, wie dies durch die Implementierung eines einfachen Image Swiper-Tutorials erreicht wird. Kommentare im Code selbst:

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
    }

}

0

Ich habe ein viewControllers-Array, das ich im UIPageViewController anzeige .

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

Wichtig hierbei ist, dass die setViewControllers- Methode von UIPageViewController keinen Delegatenrückruf gibt. Die delegierten Rückrufe repräsentieren nur Benutzerberührungsaktionen im UIPageViewController .


0

Dies ist die Lösung, die ich mir ausgedacht habe:

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

Verwendung:

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

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

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

Stellen Sie sicher, dass Sie den Anfangstitel festlegen


0

Der einfachste Weg, sich diesem IMHO zu nähern, besteht darin, das PageControl zu verwenden, um das potenzielle Ergebnis des Übergangs zu speichern und dann zurückzusetzen, wenn der Übergang abgebrochen wurde. Dies bedeutet, dass sich die Seitensteuerung ändert, sobald der Benutzer mit dem Wischen beginnt, was für mich in Ordnung ist. Dies setzt voraus, dass Sie über ein eigenes Array von UIViewControllern verfügen (in diesem Beispiel als 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
    }
}

0

Verfolgen Sie unsere aktuelle Seitenzahl in den Delegatenmethoden:

func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?     
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController

Wir verwenden einen Helfer getVC, um unsere Seitenzahl zu aktualisieren und die nächste / vorherige vc zurückzugeben. Dies ist ein guter Ort, um dies zu tun, da getVC nur aufgerufen wird, wenn es eine nächste oder vorherige VC gibt.

///Helper
func getVC(for pgNum: Int) -> BasePageVC {

    let vc = storyboard?.instantiateViewController(withIdentifier: "page"+String(pgNum)) as! BasePageVC
    vc.pageNumber = pgNum
    self.currentPage = pgNum    
    vc.data = self.data      
    return vc
}

/// Next Page
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
    guard let vc = viewController as? BasePageVC else {
        fatalError("Vc is not BasePageViewController in viewControllerAfter")
    }

    let nextPage = vc.pageNumber! + 1
    guard nextPage < self.data.pages.count - 1 else { return nil }

    return getVC(for: nextPage)
}

/// Previous Page
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
    guard let vc = viewController as? BasePageVC else {
        fatalError("Vc is not BasePageViewController in viewControllerAfter")
    }

    let prevPage = vc.pageNumber! - 1
    guard prevPage >= 0 else { return nil }

    return getVC(for: prevPage)
}

0

In schnellen 5 und folgenden Sirvine Antwort

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
        }

    }

} 

In diesem Fall ist es mir egal, welche Klasse von UIViewController eingebettet ist


-1
UIViewController *viewController = [pageViewController.viewControllers objectAtIndex:0];
NSUInteger currentIndex = [(ViewController*) viewController indexNumber];

Es wird der aktuelle Seitenindex zurückgegeben. und muss diesen Code unter der Delegatenfunktion von UIPageViewController (didFinishAnimating) verwenden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.