Bagaimana Anda tahu apa yang ditampilkan halaman / tampilan saat ini di dalam UIPageViewController
?
Saya telah mengganti viewDidAppear
metode tampilan anak saya, sehingga mereka mengirim id ke tampilan induk dalam viewDidAppear
metode mereka .
Namun, masalahnya adalah ini: saya tidak dapat menggunakan id itu sebagai id untuk halaman yang ditampilkan. karena jika pengguna membalik halaman tetapi setengah jalan memutuskan untuk berhenti membalik dan mengembalikan halaman, viewDidAppear
akan sudah dipanggil. (tampilan terlihat di belakang halaman yang digulung).
Mungkin saya hanya harus beralih ke id baru jika tampilan saat ini menghilang. Tetapi saya bertanya-tanya apakah tidak ada cara yang lebih sederhana untuk mengembalikan tampilan yang saat ini terlihat?
viewDidAppear:animated:
?Jawaban:
Anda harus melacak halaman ini secara manual. Metode delegasi
pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:
akan memberi tahu Anda kapan harus memperbarui variabel itu. Argumen terakhir dari metode initransitionCompleted:
dapat memberi tahu Anda apakah pengguna menyelesaikan transisi pergantian halaman atau tidak.sumber
Mulai iOS 6, saya telah menemukan bahwa
viewControllers
properti UIPageViewController terus diperbarui sehingga akan selalu memegang satu pengontrol tampilan yang mewakili halaman saat ini, dan tidak ada yang lain. Dengan demikian, Anda dapat mengakses halaman saat ini dengan memanggilviewControllers[0]
(Dengan asumsi Anda hanya menampilkan satu pengontrol tampilan dalam satu waktu).Larik viewController hanya memperbarui setelah halaman "terkunci" pada tempatnya, jadi jika pengguna memutuskan untuk menampilkan sebagian halaman berikutnya, halaman tersebut tidak menjadi halaman "saat ini" kecuali mereka menyelesaikan transisi.
Jika Anda ingin terus melacak "nomor halaman", tetapkan pengontrol tampilan Anda nilai indeks saat Anda membuatnya melalui metode sumber data UIPageViewController.
Jadi contohnya:
-(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; }
Tapi perhatikan komentar bahwa ini tidak bisa diandalkan.
sumber
viewControllers
properti dan saya mendapatkan pengontrol tampilan yang benar tetapi ketika saya memutar, pada metodespineLocationForInterfaceOrientation
, saya tidak mendapatkan pengontrol tampilan yang benar lagi. Jadi saya tetap mempertahankan properti currentPage saya sendiri alih-alih selalu mengandalkanviewControllers
.Sayangnya, semua metode di atas tidak membantu saya. Namun demikian, saya telah menemukan solusinya dengan menggunakan tag. Mungkin ini bukan yang terbaik, tetapi berhasil dan berharap ini membantu seseorang:
- (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; } }
Di Swift: (terima kasih kepada @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 }
Contoh: inti
sumber
Membangun Jawaban Ole…
Beginilah cara saya menerapkan 4 metode untuk melacak halaman saat ini dan memperbarui indikator halaman ke indeks yang benar:
- (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; }
sumber
self.nextIndex = self.currentIndex
daripadaself.nextIndex = 0
untuk mengembalikan indeks dengan benar ketika transisi tidak selesai. Jika tidak, Anda berisiko berakhir dengancurrentIndex
nilai 0 saat berpindah halaman dengan cepat ke suatu tempat di tengah halaman Anda.Solusi di bawah ini berhasil untuk saya.
Apple dapat menghindari banyak kerumitan dengan membuat paginasi tampilan gulir UIPageViewController asli lebih dapat dikonfigurasi. Saya harus menggunakan overlay UIView dan UIPageControl baru hanya karena pagination UIPageViewController asli tidak mendukung latar belakang transparan atau reposisi dalam bingkai tampilan.
- (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; }
sumber
Cepat 4
Tidak ada kode yang tidak perlu. 3 cara melakukannya. Menggunakan metode 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 } }
sumber
pageViewController.viewControllers
. Bagaimana Anda tahu viewControllers?. Pertama yang dimaksud?Saya melacak indeks halaman dengan menggunakan fungsi kecil dan menentukan pageIndex sebagai NSInteger statis.
-(void) setPageIndex { DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0]; pageIndex = [self.modelController indexOfViewController:theCurrentViewController]; }
dan memanggil
[self setPageIndex];
di dalam fungsi yang ditentukan oleh Ole dan juga setelah mendeteksi perubahan orientasi.sumber
Saya pertama kali menggunakan solusi Corey tetapi tidak berfungsi di iOS5 kemudian akhirnya menggunakan,
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{ if(completed) { _currentViewController = [pageViewController.viewControllers lastObject]; } }
Ini mencoba beralih melalui halaman yang berbeda dan berfungsi dengan baik untuk saat ini.
sumber
Sayangnya tidak ada di atas yang berhasil untuk saya.
Saya memiliki dua pengontrol tampilan dan ketika saya sedikit (sekitar 20px) menggulir tampilan terakhir ke belakang, itu memicu delegasi:
pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:
dan mengatakan bahwa halaman saat ini (indeks) adalah
0
yang salah.Menggunakan delegate di dalam viewController anak seperti:
- (void)ViewController:(id)VC didShowWithIndex:(long)page; // and a property @property (nonatomic) NSInteger index;
yang dipicu di dalam
viewDidAppear
seperti:- (void)viewDidAppear:(BOOL)animated { ... [self.delegate ViewController:self didShowWithIndex:self.index]; }
Bekerja untuk saya.
sumber
Ini bekerja untuk saya dengan andal
Saya memiliki UIPageController kustom. PageController.currentPage ini diperbarui dari UIViewController yang ditampilkan di 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 }
sumber
Saya telah menggunakan
view.tag
untuk sementara waktu sekarang, mencoba melacak halaman ini terlalu rumit.Dalam kode ini indeks disimpan dalam
tag
properti masing-masingview
dan digunakan untuk mengambil VC berikutnya atau sebelumnya. Menggunakan metode ini juga memungkinkan untuk membuat gulungan tak terbatas. Lihat komentar dalam kode untuk melihat solusi ini juga: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 } }
sumber
Terima kasih atas jawaban Anda, saya menghadapi masalah yang sama, harus menyimpan indeks. Saya sedikit mengubah kode saya, tempel di bawah ini:
- (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]; }
sumber
- (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
sumber
Di bawah kode demo (di Swift 2) yang mendemonstrasikan bagaimana hal ini dilakukan dengan menerapkan tutorial penyapu gambar sederhana. Komentar di kode itu sendiri:
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 } }
sumber
Saya memiliki array viewControllers, yang saya tampilkan di 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 } }
Hal yang penting untuk dicatat di sini adalah bahwa setViewControllers metode UIPageViewController tidak memberikan delegasi callback. Callback delegasi hanya mewakili tindakan sentuhan pengguna di UIPageViewController .
sumber
Ini adalah solusi yang saya dapatkan:
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) } }
Pemakaian:
let pageViewController = UIPageViewController() let delegate = DefaultUIPageViewControllerDelegate() delegate.didTransitionToViewControllerCallback = { pageViewController.title = $0.title } pageViewController.title = viewControllers.first?.title pageViewController.delegate = delegate
Pastikan untuk menyetel judul awal
sumber
Cara termudah untuk mendekati IMHO ini adalah dengan menggunakan PageControl untuk menyimpan hasil potensial dari transisi dan kemudian mengembalikannya jika transisi dibatalkan. Ini berarti bahwa kontrol halaman berubah segera setelah pengguna mulai menggesek, itu tidak masalah bagi saya. Ini mengharuskan Anda memiliki array UIViewControllers Anda sendiri (dalam contoh ini disebut
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 } }
sumber
Bagaimana kalau meminta
viewController
langsung dariUIPageViewController
(Swift 4 versi):fileprivate weak var currentlyPresentedVC: UIViewController? func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { currentlyPresentedVC = pageViewController.viewControllers?.first }
Atau, jika Anda hanya memerlukan pengontrol tampilan yang saat ini disajikan di beberapa titik waktu, cukup gunakan
pageViewController.viewControllers?.first
saat itu.sumber
Dalam 5 cepat dan jawaban sirvine berikut
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 } } }
Dalam hal ini saya tidak peduli kelas apa dari UIViewController yang disematkan
sumber
UIViewController *viewController = [pageViewController.viewControllers objectAtIndex:0]; NSUInteger currentIndex = [(ViewController*) viewController indexNumber];
Ini akan mengembalikan indeks halaman saat ini. dan harus menggunakan kode ini di bawah fungsi delegasi UIPageViewController (didFinishAnimating).
sumber