UIPageViewController: ส่งคืนมุมมองที่มองเห็นปัจจุบัน


89

คุณจะรู้ได้อย่างไรว่าหน้าปัจจุบัน / มุมมองที่แสดงอยู่ภายในUIPageViewControllerคืออะไร?

ฉันได้ลบล้างviewDidAppearเมธอดของมุมมองลูกของฉันเพื่อให้พวกเขาส่ง ID ไปยังมุมมองระดับบนสุดในviewDidAppearเมธอดของพวกเขา

อย่างไรก็ตามปัญหาคือ: ฉันไม่สามารถใช้ id นั้นเป็น id สำหรับหน้าที่แสดงได้อย่างน่าเชื่อถือ เพราะหากผู้ใช้เปลี่ยนหน้า แต่ผ่านไปครึ่งทางตัดสินใจที่จะหยุดการหมุนและวางหน้ากลับviewDidAppearจะถูกเรียกไปแล้ว (มุมมองสามารถมองเห็นได้หลังหน้าที่โค้งงอ)

บางทีฉันควรเปลี่ยนไปใช้ id ใหม่ก็ต่อเมื่อมุมมองปัจจุบันหายไป แต่ฉันสงสัยว่าไม่มีวิธีง่ายๆในการคืนมุมมองที่มองเห็นได้ในปัจจุบันหรือไม่?


คุณได้ลองใช้viewDidAppear:animated:แทนหรือไม่?
จนถึง

โอ้ใช่. ฉันใช้มัน ฉันแก้ไขคำถามเพื่อแก้ไขข้อผิดพลาดของฉัน
ม.ค.

วิธีที่คุณแก้ไขคำถามไม่สมเหตุสมผลกับฉัน ไม่ว่าคุณจะส่งรหัสนั้นจากภายใน viewWillAppear หรือจาก viewDidAppear โปรดตรวจสอบการแก้ไขของคุณอีกครั้ง
จนถึง

ขออภัยฉันแก้ไขคำถามได้ไม่ดี ฉันใช้ viewDidAppear มาตลอด ฉันหวังว่าการแก้ไขครั้งสุดท้ายของฉันจะชี้แจงสิ่งนั้น
ม.ค.

ลองดูที่นี่พวกนี้ใช้ได้กับฉันstackoverflow.com/a/36860663/4286947
theDC

คำตอบ:


104

คุณควรติดตามเพจปัจจุบันด้วยตนเอง

วิธีการมอบหมายpageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:จะบอกคุณเมื่อต้องอัปเดตตัวแปรนั้น อาร์กิวเมนต์สุดท้ายของวิธีนี้transitionCompleted:สามารถบอกคุณได้ว่าผู้ใช้ทำการเปลี่ยนหน้าเสร็จหรือไม่

จากนั้นคุณสามารถรับ View Controller ที่นำเสนอในปัจจุบันได้โดยทำ

self.viewControllers?.first

1
+1 สำหรับคำตอบที่ถูกต้อง - ฉันหวังว่าฉันจะมีโอกาสทำงานกับ UIPageViewController และรองรับ iOS5 เท่านั้น
จนถึง

ขอบคุณนั่นคือโซลูชันที่สะอาดที่ฉันกำลังมองหา ดีกว่าผู้รับมอบสิทธิ์ในหน้า
ม.ค.

3
เมื่อคุณหมุนอุปกรณ์คุณจะติดตามหน้าปัจจุบันได้อย่างไร?
Satyam

แต่คุณสามารถตั้งค่าเวอร์ชันขั้นต่ำของโครงการเป็น ios5.0
mtmurdock

84
คุณจะทราบได้อย่างไรว่าจะเพิ่มหรือลดหมายเลขหน้าปัจจุบัน
ชิม

59

ตั้งแต่ iOS 6 ฉันพบว่าviewControllersคุณสมบัติของ UIPageViewController อัปเดตอย่างต่อเนื่องเพื่อที่จะถือคอนโทรลเลอร์มุมมองเดียวที่แสดงถึงหน้าปัจจุบันเสมอและไม่มีอะไรอื่น ดังนั้นคุณสามารถเข้าถึงเพจปัจจุบันได้โดยการโทรviewControllers[0](สมมติว่าคุณแสดงตัวควบคุมมุมมองครั้งละหนึ่งตัวเท่านั้น)

อาร์เรย์ viewController จะอัปเดตเมื่อเพจ "ล็อก" เข้าที่เท่านั้นดังนั้นหากผู้ใช้ตัดสินใจที่จะเปิดเผยหน้าถัดไปบางส่วนจะไม่กลายเป็นหน้า "ปัจจุบัน" เว้นแต่ว่าจะทำการเปลี่ยนแปลงเสร็จสิ้น

หากคุณต้องการติดตาม "หมายเลขหน้า" กำหนดค่าดัชนีของตัวควบคุมมุมมองของคุณในขณะที่คุณสร้างผ่านวิธีแหล่งข้อมูล UIPageViewController


ตัวอย่างเช่น:

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

แต่โปรดทราบความคิดเห็นที่ว่านี้ไม่น่าเชื่อถือ


2
ฉันพบว่ามันไม่น่าเชื่อถือ ฉันไม่พบต้นตอของปัญหา เมื่อภาพเคลื่อนไหวเสร็จสิ้นฉันเข้าถึงviewControllersคุณสมบัติและฉันได้รับตัวควบคุมมุมมองที่ถูกต้อง แต่เมื่อฉันหมุนวิธีspineLocationForInterfaceOrientationนี้ฉันไม่ได้รับตัวควบคุมมุมมองที่ถูกต้องอีกต่อไป ดังนั้นฉันจึงยึดติดกับการรักษาคุณสมบัติ currentPage ของตัวเองแทนที่จะพึ่งพาไฟล์viewControllers.
Fábio Oliveira

น่าสนใจฉันจะเล่นกับมันเพื่อดูว่ามันทำงานอย่างไรในกรณีพิเศษเหล่านี้
Eddy Borja

2
ฉันยังพบว่ามันไม่น่าเชื่อถือ ดูเหมือนว่า Apple จะเรียกใช้ viewControllerBeforeViewController หรือ viewControllerAfterViewController สำหรับการเปิดแต่ละหน้า แต่ไม่ได้อัปเดต UIPageViewController.viewControllers ฉันไม่รู้ว่าพวกเขาจัดการอย่างไรเพื่อให้สิ่งเหล่านี้ผิดพลาด แต่พวกเขาทำ มันเพิ่มภาระงานของฉันและทำลายความชัดเจนของรหัสของฉัน (มักจะละเมิด DRY และหลักการอื่น ๆ )
Zack Morris

3
@ZackMorris. มันเหลือเชื่อมากคุณคิดถูกแล้ว มันเป็น "ช่วงเวลาสยองขวัญของ Apple" ทำไมโอ้ทำไมมันไม่รวมฟังก์ชั่นที่ชัดเจนเช่นย้ายไปทางขวาตอนนี้ฉันอยู่หน้าอะไร ฯลฯ มันเหลือเชื่อมากที่คุณไม่สามารถ "รับหน้าที่คุณอยู่ !!!" ได้
Fattie

1
self.viewControllers [0] ดูเหมือนจะทำงานได้ดีสำหรับฉัน แต่ฉันเพิ่งโทรหา setViewControllers หนึ่งครั้งในระหว่างการเริ่มต้นและปล่อยให้ส่วนที่เหลือเป็นระบบอัตโนมัติ (ทดสอบใน iOS 8.4)
Bob

45

น่าเสียดายที่วิธีการทั้งหมดข้างต้นไม่ได้ช่วยฉัน อย่างไรก็ตามฉันพบวิธีแก้ปัญหาโดยใช้แท็ก อาจไม่ใช่สิ่งที่ดีที่สุด แต่ได้ผลและหวังว่าจะช่วยใครบางคน:

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

ตัวอย่าง: ส่วนสำคัญ


3
สิ่งนี้ดูเหมือนจะตรงไปตรงมาที่สุดและได้ผลดีสำหรับฉัน ฉันตั้งค่าแท็กในการเพิ่มตัวควบคุมมุมมอง (เช่น HelpPage1ViewController * page1 = [self.storyboard instantiateViewControllerWithIdentifier: @ "page1"]; page1.view.tag = 0;) จากนั้นคุณสามารถตั้งค่าคุณสมบัติ currentPage สำหรับตัวควบคุมวิวหลักเพื่อติดตามตำแหน่งที่คุณอยู่ อย่าลืมเพิ่มโปรโตคอลทั้งสอง ("<UIPageViewControllerDataSource, UIPageViewControllerDelegate>") ไม่ใช่แค่แหล่งข้อมูลและตั้งค่าผู้รับมอบสิทธิ์เป็น self ("self.pageViewController.delegate = self;") มิฉะนั้นจะไม่มีการเรียกเมธอด สิ่งนี้ทำให้ฉันงงงวยเล็กน้อย
James Toomey

1
@VictorM วิธีนี้ใช้ไม่ได้กับฉัน ฉันมี pageViewController ที่มีรูปภาพต่างกัน มันยังคงส่งคืนแท็ก 0 สำหรับการปัดแต่ละครั้งมีความคิดว่าเหตุใดจึงเกิดขึ้น ขอบคุณล่วงหน้า
theDC

1
@VictorM ฉันใช้เวลาหลายวันในการพยายามบันทึกดัชนี แต่บังเอิญพบคำตอบนี้ฉันหวังว่าฉันจะโหวตได้ 1,000 ครั้งขอบคุณ!
Evgeniy Kleban

1
วิธีแก้ปัญหาที่ยอดเยี่ยมขอบคุณที่ใช้เวลาหลายชั่วโมงในการพยายามหลีกเลี่ยงสิ่งนี้
Vision Mkhabela

มันคืนค่าเป็น 0 เท่านั้นฉันทำอะไรผิดหรือ
N. Der

35

สร้างจากคำตอบของ Ole ...

นี่คือวิธีที่ฉันใช้ 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;

}

2
ฉันคิดว่าบรรทัดสุดท้ายควรเป็นself.nextIndex = self.currentIndexมากกว่าself.nextIndex = 0เพื่อที่จะกู้คืนดัชนีอย่างถูกต้องเมื่อการเปลี่ยนแปลงไม่เสร็จสมบูรณ์ มิฉะนั้นคุณอาจเสี่ยงที่จะลงเอยด้วยcurrentIndexค่า 0 เมื่อเลื่อนเพจไปมาตรงกลางหน้าอย่างรวดเร็ว
hverlind

1
สิ่งนี้ไม่ได้ผลสำหรับฉันอย่างเต็มที่ บางครั้ง pageViewController: willTransitionToViewControllers ไม่ได้รับการเรียกและด้วยเหตุนี้ nextIndex จึงไม่เปลี่ยนแปลงและดัชนีปัจจุบันจึงผิด
Hayden Holligan

31

วิธีแก้ปัญหาด้านล่างใช้ได้ผลสำหรับฉัน

Apple สามารถหลีกเลี่ยงความยุ่งยากได้โดยการกำหนดค่าหน้าการเลื่อนดู UIPageViewController ดั้งเดิม ฉันต้องใช้การซ้อนทับ UIView และ UIPageControl ใหม่เพียงเพราะการแบ่งหน้า UIPageViewController ดั้งเดิมไม่รองรับพื้นหลังโปร่งใสหรือการเปลี่ยนตำแหน่งภายในกรอบมุมมอง

- (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
ในสิ่งนี้คุณหมายถึงดัชนี?
Yohan

ฉันได้รับดัชนี (เช่นจำนวนเต็มที่แสดงถึงตำแหน่งของตัวควบคุมมุมมองปัจจุบันในอาร์เรย์ของ self.pageViewController.viewControllers) จากนั้นใช้สิ่งนั้นเพื่อตั้งค่าแอตทริบิวต์ currentPage ของ self.pageControl (ซึ่งคาดว่าจะเป็นค่าจำนวนเต็ม) . เข้าท่า?
sirvine

6
ดัชนีเป็นคุณสมบัติที่กำหนดเองที่นี่ฉันเชื่อว่า
Adam Johns

ปัญหาคือถ้าคุณต้องการเปลี่ยนหน้าโดยไม่ใช้วิธีการเคลื่อนไหวจะไม่ถูกเรียก
Silviu St

19

สวิฟต์ 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
    }
}

ขอบคุณพระเจ้า! pageViewController.viewControllersผมไม่ทราบเกี่ยวกับ คุณรู้จัก viewControllers ได้อย่างไร. อันดับแรกคือคำถาม?
Script Kitty

ค่อนข้างง่ายจริง ๆ อาร์เรย์ viewControllers มีตัวควบคุมมุมมองที่นำเสนอในปัจจุบันเท่านั้น
Nikola Milicevic

3
ฉันจะเข้าถึงตัวแปรดัชนีจากฟังก์ชันนั้นได้อย่างไร
N. Der

11

ฉันติดตามดัชนีเพจโดยใช้ฟังก์ชันขนาดเล็กและระบุ pageIndex เป็น NSInteger แบบคงที่

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

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

และการโทร[self setPageIndex];ภายในฟังก์ชั่นที่ Ole ระบุและหลังจากตรวจพบการเปลี่ยนแปลงในการวางแนว


5

ฉันใช้โซลูชันของ Corey เป็นครั้งแรก แต่มันไม่ทำงานบน iOS5 จากนั้นก็ใช้

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

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

พยายามเปลี่ยนไปตามหน้าต่างๆและทำงานได้ดีในตอนนี้


3

น่าเสียดายที่ไม่มีสิ่งใดที่ใช้ได้ผลกับฉัน

ฉันมีตัวควบคุมมุมมองสองตัวและเมื่อฉันเลื่อนมุมมองสุดท้ายไปข้างหลังเล็กน้อย (ประมาณ 20px) มันจะทริกเกอร์ผู้รับมอบสิทธิ์:

pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

และบอกว่าหน้าปัจจุบัน (ดัชนี) 0ผิดพลาด

การใช้ delegate ภายใน 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];
}

ทำงานให้ฉัน


3

สิ่งนี้ใช้ได้ผลกับฉันอย่างน่าเชื่อถือ

ฉันมี 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
      }

1

ฉันใช้งานview.tagมาระยะหนึ่งแล้วการพยายามติดตามหน้าปัจจุบันนั้นซับซ้อนเกินไป

ในรหัสนี้ดัชนีจะถูกเก็บไว้ในtagคุณสมบัติของแต่ละรายการviewและใช้เพื่อดึง 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
  }
}

1

ขอบคุณสำหรับคำตอบของคุณฉันประสบปัญหาที่คล้ายกันต้องจัดเก็บดัชนี ฉันแก้ไขโค้ดเล็กน้อยวางไว้ด้านล่าง:

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

ด้านล่างโค้ดสาธิต (ใน 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
    }

}

0

ฉันมีอาร์เรย์ 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


0

นี่คือวิธีแก้ปัญหาที่ฉันคิดขึ้น:

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

อย่าลืมตั้งชื่อเรื่องเริ่มต้น


0

วิธีที่ง่ายที่สุดในการเข้าถึง 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
    }
}

0

วิธีการขอ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ในเวลานั้น


0

ใน 5 อย่างรวดเร็วและทำตามคำตอบของเซอร์ไวน์

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
        }

    }

} 

ในกรณีนี้ฉันไม่สนใจว่าจะฝัง UIViewController คลาสใด


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

มันจะส่งกลับดัชนีหน้าปัจจุบัน และต้องใช้รหัสนี้ภายใต้ฟังก์ชัน delegate ของ UIPageViewController (didFinishAnimating)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.