UIPageViewController: 현재 표시되는 보기를 반환
내부에 표시된 현재 페이지/보기가 무엇인지 어떻게 알 수 있습니까?UIPageViewController
?
나는 그것을 무시했습니다.viewDidAppear
우리 를 보낼 수 입니다.viewDidAppear
방법.
그러나 문제는 이 ID를 표시된 페이지의 ID로 신뢰할 수 없다는 것입니다.만약 사용자가 페이지를 넘겼지만 중간에 페이지를 넘기기로 결정하고 페이지를 되돌린다면,viewDidAppear
이미호었습니다되출. (보기는 뒤에 .)(보기는 구부러진 페이지 뒤에 표시됩니다.)
현재 뷰가 사라지면 새로운 아이디로 전환해야 할 것 같습니다.하지만 저는 현재 보이는 뷰를 되돌릴 수 있는 더 간단한 방법이 없는지 궁금합니다.
현재 페이지를 수동으로 추적해야 합니다.
은 다음과 .pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:
에서는 해당 변수를 업데이트할 시기를 알려줍니다.과 .transitionCompleted:
사용자가 페이지 전환 전환을 완료했는지 여부를 알 수 있습니다.
그런 다음 다음 다음을 수행하여 현재 표시된 View Controller를 가져올 수 있습니다.
self.viewControllers?.first
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;
}
}
func pageViewController(pageViewController: UIPageViewController,
didFinishAnimating finished: Bool,
previousViewControllers: [UIViewController],
transitionCompleted completed: Bool)
{
guard completed else { return }
self.pageControl.currentPage = pageViewController.viewControllers!.first!.view.tag
}
예: 요지
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;
}
아래의 해결책이 저에게 효과가 있었습니다.
Apple은 기본 UIPageViewController 스크롤 뷰 페이지를 보다 쉽게 구성할 수 있도록 함으로써 많은 번거로움을 피할 수 있었습니다.네이티브 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에 의해 지정된 함수 내부 및 또한 방향의 변화를 감지한 후.
처음에 코리의 솔루션을 사용했지만 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:
현재 가 그고현인페이(인덱스)▁that▁the인가▁and▁saying▁((페▁current).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];
}
나를 위해 일했습니다.
이것은 나에게 확실하게 효과가 있습니다.
사용자 지정 UIPage 컨트롤러가 있습니다.이 페이지Controller.currentPage는 WillAppear 보기에 표시된 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];
}
당신에게 부탁하는 것은 어떻습니까?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
}
된 뷰 또는현재표보컨가필러경요사다다용합니음을우한트롤시기된▁use▁or▁contro▁simply다사▁at니ller용합,▁the▁if▁you▁need▁view▁of▁presented다▁currently또▁point는을 사용하면 됩니다.pageViewController.viewControllers?.first
- (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에 표시되는 viewController 배열이 있습니다.
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
}
}
여기서 중요한 점은 UIPageViewController의 setViewControllers 메서드는 대리자 콜백을 제공하지 않습니다.대리자 콜백은 UIPageView 컨트롤러의 사용자 터치 작업만 나타냅니다.
이것이 제가 생각해 낸 해결책입니다.
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
초기 제목을 설정해야 합니다.
UIViewController *viewController = [pageViewController.viewControllers objectAtIndex:0];
NSUInteger currentIndex = [(ViewController*) viewController indexNumber];
현재 페이지 인덱스를 반환하며 UIPageViewController(didFinishAnimating)의 대리 함수에서 이 코드를 사용해야 합니다.
이 IMHO에 접근하는 가장 간단한 방법은 페이지 컨트롤을 사용하여 전환의 잠재적 결과를 저장한 다음 전환이 취소된 경우 되돌리는 것입니다.이것은 사용자가 스와이프를 시작하자마자 페이지 컨트롤이 변경된다는 것을 의미하는데, 저는 괜찮습니다.이를 위해서는 고유한 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
}
}
swift 5에서 그리고 sirvine 대답을 따릅니다.
extension InnerDetailViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed {
guard let newIndex = embeddedViewControllers.firstIndex(where: { $0 == pageViewController.viewControllers?.last }) else { return }
print(newIndex)
currentEmbeddedViewControllerIndex = newIndex
}
}
}
이 경우 어떤 클래스의 UIViewController가 내장되어 있든 상관 없습니다.
언급URL : https://stackoverflow.com/questions/8400870/uipageviewcontroller-return-the-current-visible-view
'programing' 카테고리의 다른 글
을 통해 반복합니다.을 통해 반복합니다. (0) | 2023.07.27 |
---|---|
ios 오류와 함께 코르도바 실행..명령에 대한 오류 코드 65: 인수를 사용한 xcodebuild: (0) | 2023.07.27 |
SQL 화학에서 MariaDB의 COLUMN_GET() 사용 (0) | 2023.07.27 |
Python은 멀티스레딩을 지원합니까?실행 시간을 단축할 수 있습니까? (0) | 2023.07.27 |
PowerShell Get-Date 내부 문자열 형식 지정 (0) | 2023.07.27 |