IT

UIPageViewController : 현재 보이는 뷰를 반환

lottoking 2020. 9. 8. 08:17
반응형

UIPageViewController : 현재 보이는 뷰를 반환


어디에 현재 페이지 / 무엇인지 어떻게 알 수 UIPageViewController있습니까?

viewDidAppear자식 뷰 내 메서드를 재정 의하여 메서드에서 부모 뷰에 ID를 보냅니다 viewDidAppear.

그러나 문제는 이것입니다. 해당 ID는 안정적으로 사용할 수 없습니다. 사용자가 페이지를 넘겼지만 중간에 넘겨서 넘기기를 중지하고 페이지를 되 viewDidAppear돌리면 이미 호출 것입니다. (보기는 말린 페이지 목록이 표시됩니다).

현재보기가 사라지면 새 ID로만 전환해야 할 수도 있습니다. 하지만 현재 보이는 뷰를 반환하는 더 간단한 방법이 없는지 궁금합니다.


현재 페이지를 수동으로 추적해야합니다. 대리자 메서드 pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:는 해당 변수를 업데이트 할시 기를 알려줍니다. 메소드의 마지막 인수는 transitionCompleted:사용자가 페이지 넘기기 전환을 완료했는지 알려줍니다.


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

그러나 의견 에 유의하십시오 .


불행히도 위의 모든 방법이 도움이되지 않습니다. 그럼에도 불구하고 태그를 사용하여 해결책을 찾았습니다. 누군가에게 도움이되기를 바랍니다.

- (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은 레이아웃 UI PageViewController 스크롤 뷰 페이지 매김을보다 구성 가능하게 만들어 많은 번거 로움을 피할 수 있습니다. 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;
}

스위프트 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];
    }
}

다른 페이지로 전환을 시도하고 현재는 잘 작동합니다.


불행히도 위의 아무것도 나를 위해 작동하지 않습니다.

두 개의 뷰가 있고 약간의 (약 20px) 마지막 뷰를 뒤로 스크롤하면 델리게이트가 트리거됩니다.

pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

현재 페이지 (인덱스) 0가 잘못 됐습니다 .

다음과 같은 마이너스 뷰 컨트롤러 내에서 대리를 사용합니다.

- (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는 viewWillAppear에 UIViewController에서 업데이트됩니다.

   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를 가져 오는 데 사용됩니다. 이 방법을 사용하면 무한 스크롤을 만들 수도 있습니다. 이 솔루션을 보려면 코드의 주석을 확인하십시오.

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

아래의 테스트 코드 (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
    }

}

UIPageViewController에 표시되는 viewControllers 배열이 있습니다 .

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을 사용하여 전환의 결과를 저장 한 다음 전환이 취소 된 경우 되 돌리는 것입니다. 이 사용자가 스 와이프를 시작하자마자 페이지 컨트롤이 변경됨을 의미합니다. 이를 UIViewController의 고유 한 한 배열이 있어야합니다 (이 예제에서는 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를 사용하여 페이지 번호를 업데이트하고 다음 / 이전 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)
}

(Swift 4 버전) viewController에서 직접 요청하는 방법 UIPageViewController:

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

현재 페이지 공사를 반환합니다. UIPageViewController (didFinishAnimating)의 델리게이트 함수 에서이 코드를 사용합니다.

참고 URL : https://stackoverflow.com/questions/8400870/uipageviewcontroller-return-the-current-visible-view

반응형

'IT' 카테고리의 다른 글

단위 테스트는 얼마나 깊습니까?  (0) 2020.09.08
고유 한 임의의 생성 생성  (0) 2020.09.08
목록의 표준 표준  (0) 2020.09.08
Gmail 및 NodeJS를 사용하는 Nodemailer  (0) 2020.09.08
클래스 클래스 JavaScript  (0) 2020.09.08