UIPageViewController: trả về chế độ xem hiện tại


89

Làm thế nào để bạn biết trang / chế độ xem hiện tại được hiển thị bên trong một UIPageViewController?

Tôi đã ghi đè viewDidAppearphương thức của các chế độ xem con của tôi, để chúng gửi một id đến chế độ xem chính trong viewDidAppearphương thức của chúng .

Tuy nhiên, vấn đề là ở đây: tôi không thể tin cậy sử dụng id đó làm id cho trang được hiển thị. bởi vì nếu người dùng lật trang nhưng được nửa chừng quyết định dừng lật và đặt trang trở lại, viewDidAppearthì sẽ đã được gọi. (chế độ xem có thể nhìn thấy đằng sau trang được cuộn tròn).

Có lẽ tôi chỉ nên chuyển sang một id mới nếu chế độ xem hiện tại biến mất. Nhưng không biết có cách nào đơn giản hơn để trả lại chế độ xem đang hiển thị không?


Bạn đã thử sử dụng viewDidAppear:animated:thay thế chưa?
Đến

O, vâng. Tôi đã sử dụng nó. Tôi đã chỉnh sửa câu hỏi để sửa lỗi của mình.
Ngày

Cách bạn chỉnh sửa câu hỏi không có ý nghĩa đối với tôi. Bạn có thể gửi id đó từ bên trong viewWillAppear hoặc từ viewDidAppear. Vui lòng kiểm tra lại chỉnh sửa của bạn.
Đến

Xin lỗi, tôi đã làm sai công việc chỉnh sửa câu hỏi. Tôi đã sử dụng viewDidAppear. Tôi hy vọng chỉnh sửa cuối cùng của tôi làm rõ điều đó.
Ngày

Hãy xem ở đây các bạn, điều này phù hợp với tôi stackoverflow.com/a/36860663/4286947
theDC

Câu trả lời:


103

Bạn nên theo dõi trang hiện tại theo cách thủ công. Phương thức ủy nhiệm pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:sẽ cho bạn biết khi nào cập nhật biến đó. Đối số cuối cùng của phương thức này transitionCompleted:có thể cho bạn biết liệu người dùng đã hoàn thành chuyển đổi lượt trang hay chưa.


1
+1 cho câu trả lời đúng - Tôi ước mình có cơ hội làm việc với UIPageViewController và chỉ hỗ trợ iOS5.
Cho đến

Cảm ơn, đó chính xác là giải pháp sạch mà tôi đang tìm kiếm. tốt hơn các đại biểu trên các trang.
Ngày

3
Khi bạn xoay thiết bị, làm thế nào để bạn theo dõi trang hiện tại?
Satyam

@till bạn có thể, chỉ cần đặt phiên bản tối thiểu của dự án của bạn để ios5.0
mtmurdock

83
Làm thế nào bạn có thể biết nên tăng hay giảm số trang hiện tại?
shim

59

Kể từ iOS 6, tôi nhận thấy rằng thuộc viewControllerstính của UIPageViewController liên tục cập nhật để nó luôn giữ bộ điều khiển một chế độ xem đại diện cho trang hiện tại và không có gì khác. Do đó, bạn có thể truy cập trang hiện tại bằng cách gọi viewControllers[0](Giả sử bạn chỉ hiển thị một bộ điều khiển chế độ xem tại một thời điểm).

Mảng viewController chỉ cập nhật khi trang "khóa" vào vị trí, vì vậy nếu người dùng quyết định để lộ một phần trang tiếp theo, nó sẽ không trở thành trang "hiện tại" trừ khi họ hoàn thành quá trình chuyển đổi.

Nếu bạn muốn theo dõi "số trang", hãy chỉ định bộ điều khiển chế độ xem của bạn một giá trị chỉ mục khi bạn tạo chúng thông qua các phương thức nguồn dữ liệu UIPageViewController.


Ví dụ:

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

Nhưng lưu ý các ý kiến rằng điều này là không đáng tin cậy.


2
Tôi thấy nó không đáng tin cậy. Tôi không thể tìm thấy nguồn gốc của vấn đề. Khi hoạt ảnh kết thúc, tôi truy cập thuộc viewControllerstính và tôi nhận được bộ điều khiển chế độ xem phù hợp nhưng khi tôi xoay, trên phương thức spineLocationForInterfaceOrientation, tôi không nhận được bộ điều khiển chế độ xem chính xác nữa. Vì vậy, tôi cố gắng duy trì thuộc tính currentPage của riêng mình thay vì luôn dựa vào viewControllers.
Fábio Oliveira

Thật thú vị, tôi sẽ chơi với nó một chút để xem nó hoạt động như thế nào trong những trường hợp đặc biệt này
Eddy Borja

2
Tôi cũng thấy nó không đáng tin cậy. Có vẻ như Apple chỉ gọi viewControllerBeforeViewController hoặc viewControllerAfterViewController cho mỗi lượt trang, nhưng không cập nhật UIPageViewController.viewControllers. Tôi không biết làm thế nào họ tiếp tục quản lý để làm sai những điều này, nhưng họ đã làm. Nó thực sự làm tăng khối lượng công việc của tôi và phá vỡ sự rõ ràng của mã của tôi (thường vi phạm DRY và các nguyên tắc khác).
Zack Morris

3
@ZackMorris. Nó hoàn toàn không thể tin được, bạn hoàn toàn đúng. Đó là một "khoảnh khắc kinh dị của Apple." Tại sao oh tại sao họ không bao gồm các chức năng rõ ràng như di chuyển một sang phải, tôi đang ở trang nào, v.v. Thật khó tin là bạn không thể "lấy được trang bạn đang truy cập !!!"
Fattie

1
self.viewControllers [0] dường như hoạt động tốt đối với tôi. Nhưng tôi chỉ gọi setViewControllers một lần trong khi khởi tạo và để phần còn lại cho tự động hóa. (được thử nghiệm trong iOS 8.4)
Bob

45

Thật không may, tất cả các phương pháp trên đã không giúp tôi. Tuy nhiên, tôi đã tìm ra giải pháp bằng cách sử dụng các thẻ. Có thể nó không phải là tốt nhất, nhưng nó hoạt động và hy vọng nó sẽ giúp ai đó:

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

Bằng Swift: (cảm ơn @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
}

Ví dụ: ý chính


3
Điều này có vẻ đơn giản nhất và làm việc tốt cho tôi. Tôi đã đặt các thẻ khi thêm bộ điều khiển chế độ xem (ví dụ: HelpPage1ViewController * page1 = [self.storyboard InstantiateViewControllerWithIdentifier: @ "page1"]; page1.view.tag = 0;). Sau đó, bạn có thể đặt thuộc tính currentPage cho bộ điều khiển chế độ xem chính để theo dõi vị trí của bạn. Đảm bảo thêm cả hai giao thức ("<UIPageViewControllerDataSource, UIPageViewControllerDelegate>"), không chỉ nguồn dữ liệu và đặt đại biểu thành self ("self.pageViewController.delegate = self;") nếu không phương thức sẽ không được gọi. Điều này làm tôi bối rối một chút.
James Toomey

1
@VictorM giải pháp này không hoạt động với tôi. Tôi có một pageViewController với các hình ảnh khác nhau. Nó tiếp tục trả về thẻ 0 cho mỗi lần vuốt, bất kỳ ý tưởng nào tại sao điều này xảy ra? Cảm ơn trước
theDC

1
@VictorM Tôi đã dành nhiều ngày để cố gắng lưu chỉ mục, nhưng tình cờ tìm thấy câu trả lời này, tôi ước tôi có thể ủng hộ 1000 lần, cảm ơn bạn!
Evgeniy Kleban

1
Lớn giải pháp Cảm ơn đã mất nhiều giờ cố gắng để làm được việc này
Vision Mkhabela

Nó chỉ trả về giá trị bằng 0. Tôi có đang làm gì sai không
N. Der

35

Xây dựng trên Câu trả lời của Ole…

Đây là cách tôi triển khai 4 phương pháp để theo dõi trang hiện tại và cập nhật chỉ báo trang thành chỉ mục chính xác:

- (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
Tôi nghĩ rằng dòng cuối cùng nên self.nextIndex = self.currentIndexchứ không phải là self.nextIndex = 0để khôi phục lại đúng chỉ số khi chuyển đổi không được hoàn thành. Nếu không, bạn có nguy cơ kết thúc bằng currentIndexgiá trị 0 khi nhanh chóng phân trang qua lại ở đâu đó giữa các trang của bạn.
hverlind

1
Điều này không hoàn toàn phù hợp với tôi. Đôi khi, pageViewController: willTransitionToViewControllers không được gọi và do đó nextIndex không được thay đổi, và chỉ mục hiện tại sau đó sai.
Hayden Holligan

31

Giải pháp dưới đây đã làm việc cho tôi.

Apple có thể tránh được nhiều rắc rối bằng cách làm cho phân trang chế độ xem cuộn UIPageViewController có thể cấu hình tốt hơn. Tôi đã phải dùng đến việc phủ một UIView và UIPageControl mới chỉ vì phân trang UIPageViewController gốc sẽ không hỗ trợ nền trong suốt hoặc định vị lại trong khung xem.

- (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
trong điều này bạn có nghĩa là gì của chỉ mục?
Yohan

Tôi đang nhận chỉ mục (tức là số nguyên đại diện cho vị trí của bộ điều khiển chế độ xem hiện tại trong mảng self.pageViewController.viewControllers) và sau đó sử dụng nó để đặt thuộc tính currentPage của self.pageControl (đòi hỏi giá trị nguyên) . Có lý?
sirvine

6
chỉ mục là thuộc tính tùy chỉnh ở đây tôi tin rằng
Adam Johns

Vấn đề ở đây là nếu bạn muốn thay đổi trang mà không cần phương pháp hoạt hình sẽ không được gọi là
Silviu St

19

Swift 4

Không có mã không cần thiết. 3 cách thực hiện. Sử dụng phương thức 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
    }
}

Cảm ơn chúa! Tôi không biết về pageViewController.viewControllers. Làm thế nào để bạn biết viewControllers?. Đầu tiên là một trong những câu hỏi?
Script Kitty

Thực ra, khá đơn giản, mảng viewControllers chỉ chứa bộ điều khiển chế độ xem hiện được trình bày.
Nikola Milicevic

2
làm cách nào để truy cập biến chỉ mục ra khỏi hàm đó?
N. Der

11

Tôi đang theo dõi chỉ mục trang bằng cách sử dụng một chức năng nhỏ và chỉ định pageIndex là NSInteger tĩnh.

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

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

và gọi [self setPageIndex];bên trong hàm được chỉ định bởi Ole và cả sau khi phát hiện sự thay đổi trong hướng.


5

Lần đầu tiên tôi sử dụng giải pháp của Corey nhưng nó không hoạt động trên iOS5 sau đó cuối cùng sử dụng,

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

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

Nó đã thử chuyển qua các trang khác nhau và hiện tại nó hoạt động tốt.


3

Thật không may, không có gì ở trên làm việc cho tôi.

Tôi có hai bộ điều khiển chế độ xem và khi tôi hơi (khoảng 20px) cuộn chế độ xem cuối cùng về phía sau, nó sẽ kích hoạt đại biểu:

pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

và nói rằng trang (chỉ mục) hiện tại 0là sai.

Sử dụng ủy nhiệm bên trong chế độ xem con, điều khiển như sau:

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

// and a property

@property (nonatomic) NSInteger index;

được kích hoạt bên trong viewDidAppearnhư:

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

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

Đã làm cho tôi.


3

Điều này làm cho tôi đáng tin cậy

Tôi có một UIPageController tùy chỉnh. Trang nàyController.currentPage được cập nhật từ UIViewController được hiển thị trong 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
      }

1

Tôi đã sử dụng view.tagmột thời gian rồi, việc cố gắng theo dõi trang hiện tại quá phức tạp.

Trong mã này, chỉ mục được lưu trữ trong thuộc tagtính của mỗi chỉ mục viewvà được sử dụng để tìm nạp VC tiếp theo hoặc trước đó. Sử dụng phương pháp này, bạn cũng có thể tạo một cuộn vô hạn. Kiểm tra bình luận trong mã để xem giải pháp này cũng như:

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

Cảm ơn câu trả lời của bạn guys, tôi phải đối mặt với vấn đề tương tự, đã phải lưu trữ chỉ mục. Tôi sửa đổi một chút mã của mình, dán nó vào bên dưới:

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

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

Dưới đây là mã demo (trong Swift 2) minh họa cách thực hiện điều này bằng cách triển khai hướng dẫn swiper hình ảnh đơn giản. Nhận xét trong chính mã:

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

Tôi có một mảng viewControllers, mà tôi hiển thị trong 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
}
}

Điều quan trọng cần lưu ý ở đây là setViewControllers phương pháp UIPageViewController không đưa ra bất cứ callback delegate. Các lệnh gọi lại ủy quyền chỉ đại diện cho các thao tác chạm của người dùng trong UIPageViewController .


0

Đây là giải pháp tôi đã nghĩ ra:

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

Sử dụng:

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

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

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

Đảm bảo đặt tiêu đề ban đầu


0

Cách đơn giản nhất để tiếp cận IMHO này là sử dụng PageControl để lưu trữ kết quả tiềm năng của quá trình chuyển đổi và sau đó hoàn nguyên nếu quá trình chuyển đổi bị hủy. Điều này có nghĩa là kiểm soát trang sẽ thay đổi ngay sau khi người dùng bắt đầu vuốt, theo tôi điều này là ổn. Điều này yêu cầu bạn phải có mảng UIViewControllers của riêng mình (trong ví dụ này được gọi là 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

Còn về việc yêu cầu viewControllertrực tiếp từ UIPageViewController(phiên bản Swift 4):

fileprivate weak var currentlyPresentedVC: UIViewController?

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

Hoặc, nếu bạn chỉ cần bộ điều khiển chế độ xem hiện được trình bày tại một thời điểm nào đó, chỉ cần sử dụng pageViewController.viewControllers?.firsttại thời điểm đó.


0

Trong câu trả lời nhanh 5 và sau sirvine

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
        }

    }

} 

Trong trường hợp này, tôi không quan tâm lớp UIViewController nào được nhúng


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

Nó sẽ trả về chỉ mục trang hiện tại. và phải sử dụng mã này trong chức năng ủy quyền của UIPageViewController (didFinishAnimating).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.