質問

現在のページ/ビューが何であるかをどのように知っていますか UIPageViewController?

私はオーバーライドしました viewDidAppear 私の子供の見解の方法。 viewDidAppear 方法。

ただし、問題は次のとおりです。表示されたページのIDとしてそのIDを確実に使用することはできません。ユーザーがページをめくるが、途中でターニングを停止してページを元に戻すことを決定した場合、 viewDidAppear すでに呼ばれています。 (ビューは、カールしたページの後ろに表示されます)。

多分私は、現在のビューが消えた場合にのみ新しいIDに切り替える必要があります。しかし、現在見えるビューを返すより簡単な方法がないのだろうか?

役に立ちましたか?

解決

現在のページを手動で追跡する必要があります。デリゲートメソッド pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted: その変数をいつ更新するかを教えてくれます。メソッドの最後の引数 transitionCompleted: ユーザーがページターントランジションを完了したかどうかを知ることができます。

他のヒント

iOS 6の時点で、私はそれを発見しました viewControllers UipageViewControllerのプロパティは常に更新され、現在のページを表す1つのビューコントローラーを常に保持します。したがって、呼び出して現在のページにアクセスできます viewControllers[0] (一度に1つのビューコントローラーのみを表示すると仮定します)。

ViewControllerアレイは、ページが所定の位置に「ロック」された後にのみ更新されるため、ユーザーが次のページを部分的に表示することを決定した場合、移行を完了しない限り「現在」ページになりません。

「ページ番号」を追跡する場合は、UIPAGEViewController DataSourceメソッドを介して作成するときに、ビューコントローラーをインデックス値に割り当てます。


したがって、例:

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

しかし コメントに注意してください これは信頼できないこと。

残念ながら、上記の方法はすべて私を助けませんでした。それにもかかわらず、タグを使用してソリューションを見つけました。それが最高ではないかもしれませんが、それはうまくいき、それが誰かを助けることを願っています:

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

Swift: (ありがとう @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
}

例: 要旨

オレの答えに基づいて…

これは、現在のページを追跡し、ページインジケーターを正しいインデックスに更新する4つのメソッドを実装した方法です。

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

}

以下の解決策は私のために機能しました。

Appleは、ネイティブのuipageViewController Surloll View Paginationをより構成可能にすることで、多くの手間を避けることができます。ネイティブのuipageViewControllerページネーションがビューフレーム内の透明な背景や再配置をサポートしないという理由だけで、新しいUIViewとUipageControlのオーバーレイに頼らなければなりませんでした。

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

Swift 4

不要なコードはありません。それを行う3つの方法。使用 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
    }
}

小さな関数を使用してPageIndexを静的nsintegerとして指定することにより、ページインデックスを追跡しています。

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

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

と電話 [self setPageIndex]; OLEによって指定された関数内および方向の変化を検出した後。

私は最初にCoreyのソリューションを使用しましたが、iOS5で作業していなかった後、使用しました。

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

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

さまざまなページを切り替えてみましたが、今のところうまく機能しています。

残念ながら、私にとっては上に何もうまくいきません。

私は2つのビューコントローラーを持っています、そして、私が少し(約20px)最後のビューを後方にスクロールするとき、それはデリゲートをトリガーします:

pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

そして、現在のページ(インデックス)は 0 これは間違っています。

Delegate Inside Child ViewControllerを使用してください。

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

// and a property

@property (nonatomic) NSInteger index;

それは内部でトリガーされます viewDidAppear お気に入り:

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

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

私のために働いた。

これは私にとって確実に機能します

カスタムのuipagecontrollerがあります。このpagecontroller.currentPageは、表示されているuiviewcontrollerから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
      }

私は使用しています view.tag しばらくの間、現在のページを追跡しようとすることは複雑すぎました。

このコードでは、インデックスが内部に保存されます tag それぞれの財産 view 次のVCまたは以前のVCを取得するために使用されます。この方法を使用すると、無限のスクロールを作成することもできます。このソリューションを表示するには、コードのコメントをご覧ください。

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

あなたの答えをありがとう、私は同様の問題に直面し、インデックスを保存する必要がありました。コードを少し変更し、以下に貼り付けます。

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

Simple Image Swiperチュートリアルを実装することでこれがどのように行われるかを示すデモコード(Swift 2)以下。コード自体のコメント:

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
    }

}

ViewControllersアレイがあります。 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
}
}

ここで注意すべき重要なことは、それです SetViewControllers の方法 uipageviewcontroller デリゲートコールバックは提供しません。デリゲートコールバックは、のユーザータッチアクションのみを表します uipageviewcontroller.

これは私が思いついた解決策です:

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

使用法:

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

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

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

必ず最初のタイトルを設定してください

このiMhoにアプローチする最も簡単な方法は、PageControlを使用して遷移の潜在的な結果を保存し、移行がキャンセルされた場合に戻ることです。これは、ユーザーがスワイプを開始するとすぐにページコントロールが変更されることを意味します。これは私には問題ありません。これには、uiviewcontrollersの独自の配列が必要です(この例では、 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
    }
}

デリゲートの方法で現在のページ番号を追跡する:

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

ヘルパーGETVCを使用してページ番号を更新し、Next/Prev VCを返します。 GETVCは次または以前のVCがある場合にのみ呼び出されるため、これを行うのに適した場所です。

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

を求めてみませんか viewController から直接 UIPageViewController (Swift 4バージョン):

fileprivate weak var currentlyPresentedVC: UIViewController?

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

または、ある時点で現在提示されているビューコントローラーが必要な場合は、単に使用するだけです pageViewController.viewControllers?.first その時。

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

現在のページインデックスを返します。 UPAGEViewController(didfinishanimating)のデリゲート関数の下でこのコードを使用する必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top