답변:
예, 다음과 같은 방법으로 가능합니다.
- (void)setViewControllers:(NSArray *)viewControllers
direction:(UIPageViewControllerNavigationDirection)direction
animated:(BOOL)animated
completion:(void (^)(BOOL finished))completion;`
이는 페이지에서 첫 번째보기 컨트롤러를 설정하는 데 사용 된 것과 동일한 방법입니다. 마찬가지로 다른 페이지로 이동할 수도 있습니다.
왜 viewControllers
단일 뷰 컨트롤러가 아닌 배열입니까?
이는 페이지보기 컨트롤러에 iBook과 같은 "스파인"이있어 한 번에 2 페이지의 컨텐츠를 표시 할 수 있기 때문입니다. 한 번에 1 페이지의 내용을 표시하는 경우 1 요소 배열로 전달하십시오.
Swift의 예 :
pageContainer.setViewControllers([displayThisViewController], direction: .Forward, animated: true, completion: nil)
이 작업도 필요했기 때문에이 작업을 수행하는 방법에 대해 자세히 설명하겠습니다.
참고 : 나는 당신이 당신의 생성을위한 표준 템플릿 양식을 사용하는 가정 UIPageViewController
- 가지고있는 두 구조를 modelViewController
하고 dataViewController
그것을 호출 할 때를 만들었습니다. 내가 쓴 내용을 이해하지 못하면 다시 돌아가서 새 프로젝트를 작성하십시오.UIPageViewController
십시오. 당신은 그때 이해합니다.
따라서 특정 페이지로 넘어가려면 위에 나열된 다양한 방법을 설정해야합니다. 이 연습에서는 두 개의 뷰가 표시된 풍경 뷰 라고 가정합니다 . 또한 IBAction으로 구현하여 버튼 누르기 또는 그렇지 않은 작업으로 수행 할 수 있습니다. 선택기를 호출하고 필요한 항목을 전달하는 것만 큼 쉽습니다.
따라서이 예에서는 표시 될 두 개의 뷰 컨트롤러가 필요하며 선택적으로 책에서 앞으로 또는 뒤로 이동할 수 있습니다.
4 페이지와 5 페이지로 이동하여 앞으로 미끄러짐을 사용하는 위치를 하드 코딩했습니다. 여기에서 당신이해야 할 일은이 항목을 얻는 데 도움이되는 변수를 전달하는 것입니다 ...
-(IBAction) flipToPage:(id)sender {
// Grab the viewControllers at position 4 & 5 - note, your model is responsible for providing these.
// Technically, you could have them pre-made and passed in as an array containing the two items...
DataViewController *firstViewController = [self.modelController viewControllerAtIndex:4 storyboard:self.storyboard];
DataViewController *secondViewController = [self.modelController viewControllerAtIndex:5 storyboard:self.storyboard];
// Set up the array that holds these guys...
NSArray *viewControllers = nil;
viewControllers = [NSArray arrayWithObjects:firstViewController, secondViewController, nil];
// Now, tell the pageViewContoller to accept these guys and do the forward turn of the page.
// Again, forward is subjective - you could go backward. Animation is optional but it's
// a nice effect for your audience.
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
// Voila' - c'est fin!
}
다음은 단일 페이지보기에 대한 다른 코드 예제입니다. viewControllerAtIndex 에 대한 구현 은 여기에서 생략되며 주어진 인덱스에 대해 올바른보기 컨트롤러를 리턴해야합니다.
- (void)changePage:(UIPageViewControllerNavigationDirection)direction {
NSUInteger pageIndex = ((FooViewController *) [_pageViewController.viewControllers objectAtIndex:0]).pageIndex;
if (direction == UIPageViewControllerNavigationDirectionForward) {
pageIndex++;
}
else {
pageIndex--;
}
FooViewController *viewController = [self viewControllerAtIndex:pageIndex];
if (viewController == nil) {
return;
}
[_pageViewController setViewControllers:@[viewController]
direction:direction
animated:YES
completion:nil];
}
전화로 페이지를 변경할 수 있습니다
[self changePage:UIPageViewControllerNavigationDirectionReverse];
[self changePage:UIPageViewControllerNavigationDirectionForward];
나는 여기에 완전히 빠져있을 수 있지만이 솔루션은 다른 많은 사람들이 제안한 것보다 훨씬 간단 해 보입니다.
extension UIPageViewController {
func goToNextPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) {
if let currentViewController = viewControllers?[0] {
if let nextPage = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) {
setViewControllers([nextPage], direction: .forward, animated: animated, completion: completion)
}
}
}
}
이 코드는 나에게 잘 작동했습니다. 감사합니다.
이것이 내가 한 일입니다. 앞으로 또는 뒤로 스테핑하는 방법과 특정 페이지로 직접 이동하는 방법 세로보기에서 6 페이지 문서입니다. pageViewController 템플릿의 RootController 구현에 붙여 넣으면 정상적으로 작동합니다.
-(IBAction)pageGoto:(id)sender {
//get page to go to
NSUInteger pageToGoTo = 4;
//get current index of current page
DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0];
NSUInteger retreivedIndex = [self.modelController indexOfViewController:theCurrentViewController];
//get the page(s) to go to
DataViewController *targetPageViewController = [self.modelController viewControllerAtIndex:(pageToGoTo - 1) storyboard:self.storyboard];
DataViewController *secondPageViewController = [self.modelController viewControllerAtIndex:(pageToGoTo) storyboard:self.storyboard];
//put it(or them if in landscape view) in an array
NSArray *theViewControllers = nil;
theViewControllers = [NSArray arrayWithObjects:targetPageViewController, secondPageViewController, nil];
//check which direction to animate page turn then turn page accordingly
if (retreivedIndex < (pageToGoTo - 1) && retreivedIndex != (pageToGoTo - 1)){
[self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
}
if (retreivedIndex > (pageToGoTo - 1) && retreivedIndex != (pageToGoTo - 1)){
[self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:NULL];
}
}
-(IBAction)pageFoward:(id)sender {
//get current index of current page
DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0];
NSUInteger retreivedIndex = [self.modelController indexOfViewController:theCurrentViewController];
//check that current page isn't first page
if (retreivedIndex < 5){
//get the page to go to
DataViewController *targetPageViewController = [self.modelController viewControllerAtIndex:(retreivedIndex + 1) storyboard:self.storyboard];
//put it(or them if in landscape view) in an array
NSArray *theViewControllers = nil;
theViewControllers = [NSArray arrayWithObjects:targetPageViewController, nil];
//add page view
[self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
}
}
-(IBAction)pageBack:(id)sender {
//get current index of current page
DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0];
NSUInteger retreivedIndex = [self.modelController indexOfViewController:theCurrentViewController];
//check that current page isn't first page
if (retreivedIndex > 0){
//get the page to go to
DataViewController *targetPageViewController = [self.modelController viewControllerAtIndex:(retreivedIndex - 1) storyboard:self.storyboard];
//put it(or them if in landscape view) in an array
NSArray *theViewControllers = nil;
theViewControllers = [NSArray arrayWithObjects:targetPageViewController, nil];
//add page view
[self.pageViewController setViewControllers:theViewControllers direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:NULL];
}
}
스위프트 4 :
pagecontroller view controller에서 next를 탭하고 pageControl 인덱스를 업데이트 할 때 다음 컨트롤러로 이동해야했기 때문에 이것이 가장 쉽고 간단한 솔루션 이었습니다 .
let pageController = self.parent as! PageViewController
pageController.setViewControllers([parentVC.orderedViewControllers[1]], direction: .forward, animated: true, completion: nil)
pageController.pageControl.currentPage = 1
dataSource의 메소드를 사용하는 것은 어떻습니까?
UIViewController *controller = [pageViewController.dataSource pageViewController:self.pageViewController viewControllerAfterViewController:pageViewController.viewControllers.firstObject];
[pageViewController setViewControllers:@[controller] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
역으로 유사합니다.
에서 스위프트 :
import UIKit
extension HomeViewController {
// MARK: - Carousel management.
func startTimerForMovingCarousel(let numberOfSecondsBetweenFiringsOfTheTimer: NSTimeInterval) {
if (self.timerForMovingCarousel == nil) {
self.timerForMovingCarousel = NSTimer.scheduledTimerWithTimeInterval(numberOfSecondsBetweenFiringsOfTheTimer,
target: self,
selector: "moveCarousel",
userInfo: nil,
repeats: true)
}
}
func moveCarousel() {
println("I move the carousel.")
let currentContentViewControllerDisplayed = self.pageViewController!.viewControllers[0] as! ContentViewController
var index: Int = currentContentViewControllerDisplayed.index
if index == self.arrayViewControllers.count - 1 {
index = 0
} else {
++index
}
let contentViewControllerToDisplay = self.arrayViewControllers[index] as! ContentViewController
self.pageViewController.setViewControllers([contentViewControllerToDisplay],
direction: UIPageViewControllerNavigationDirection.Forward,
animated: true,
completion: nil)
self.pageControl.currentPage = contentViewControllerToDisplay.index
}
func invalidateTimerForMovingCarousel() {
if (self.timerForMovingCarousel != nil) {
self.timerForMovingCarousel.invalidate()
self.timerForMovingCarousel = nil
}
}
}
그러나이 'self.pageViewController setViewControllers'메서드 호출을 사용하면 되 돌린 페이지에 대해 viewController에서 'viewDidDissapear'를 호출하지 않는 반면 페이지를 수동으로 돌리면 무시 된 페이지에서 viewDidDissapear를 호출합니다. 이것이 내 추락의 원인이라고 생각합니다
"제공된 뷰 컨트롤러 수 (0)가 요청 된 전환에 필요한 수 (1)와 일치하지 않습니다."
또한 스 와이프 동작에서 예상 한 것과 정확히 일치하는 PageViewController에서 왼쪽으로 탐색하는 버튼이 필요했습니다.
자연스럽게 스 와이프 탐색을 처리하기 위해 " pageViewController : viewControllerBeforeViewController " 안에 몇 가지 규칙이 이미 있으므로 버튼을 사용하여 해당 코드를 모두 재사용하고 특정 인덱스를 사용할 여유가 없었습니다. 하고 이전과 같이 페이지에 도달 을 대답했다. 그래서 대체 솔루션을 사용해야했습니다.
다음 코드는 내 사용자 정의 ViewController 내부의 속성이며 척추가 중간으로 설정된 페이지 뷰 컨트롤러 용입니다.
Navigate Left 버튼에 대해 작성한 코드는 다음과 같습니다.
- (IBAction)btnNavigateLeft_Click:(id)sender {
// Calling the PageViewController to obtain the current left page
UIViewController *currentLeftPage = [_pageController.viewControllers objectAtIndex:0];
// Creating future pages to be displayed
NSArray *newDisplayedPages = nil;
UIViewController *newRightPage = nil;
UIViewController *newLeftPage = nil;
// Calling the delegate to obtain previous pages
// My "pageViewController:viewControllerBeforeViewController" method returns nil if there is no such page (first page of the book).
newRightPage = [self pageViewController:_pageController viewControllerBeforeViewController:currentLeftPage];
if (newRightPage) {
newLeftPage = [self pageViewController:_pageController viewControllerBeforeViewController:newRightPage];
}
if (newLeftPage) {
newDisplayedPages = [[NSArray alloc] initWithObjects:newLeftPage, newRightPage, nil];
}
// If there are two new pages to display, show them with animation.
if (newDisplayedPages) {
[_pageController setViewControllers:newDisplayedPages direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:nil];
}
}
여기에서 올바른 탐색 버튼을 만들기 위해 매우 비슷한 작업을 수행 할 수 있습니다.
경우 && 당신은 페이지 스크롤을 통해 & 또한 페이지의 ViewController에서 사용자 정의 버튼을 클릭하여 탐색 할 O입니다 PAGE CONTROL은 현재 페이지를 표시하는 경우, 아래에 도움이 될 수 있습니다.
//Set Delegate & Data Source for PageView controller [Say in View Did Load]
self.pageViewController.dataSource = self;
self.pageViewController.delegate = self;
// Delegates called viewControllerBeforeViewController when User Scroll to previous page
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController{
[_nextBtn setTitle:@"Next" forState:UIControlStateNormal];
NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
if (index == NSNotFound){
return nil;
}else if (index > 0){
index--;
}else{
return nil;
}
return [self viewControllerAtIndex:index];
}
// 사용자가 다음 페이지로 스크롤 할 때 viewControllerAfterViewController 호출
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController{
NSUInteger index = ((PageContentViewController*) viewController).pageIndex;
if (index == NSNotFound){
return nil;
}else if (index < 3){
index++;
}else{
return nil;
}
return [self viewControllerAtIndex:index];}
//Delegate called while transition of pages. The need to apply logic in this delegate is to maintain the index of current page.
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers{
buttonIndex = (int)((PageContentViewController*) pendingViewControllers.firstObject).pageIndex;
}
-(void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{
if (buttonIndex == 0){
_backButton.hidden = true;
}else if (buttonIndex == [self.pageImages count] - 1){
_backButton.hidden = false;
[_nextBtn setTitle:@"Begin" forState:UIControlStateNormal];
}else{
_backButton.hidden = false;
}
}
// 맞춤형 버튼 (이전 및 다음) 로직
-(void)backBtnClicked:(id)sender{
if (buttonIndex > 0){
buttonIndex -= 1;
}
if (buttonIndex < 1) {
_backButton.hidden = YES;
}
if (buttonIndex >=0) {
[_nextBtn setTitle:@"Next" forState:UIControlStateNormal];
PageContentViewController *startingViewController = [self viewControllerAtIndex:buttonIndex];
NSArray *viewControllers = @[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
}
}
-(void)nextBtnClicked:(id)sender{
if (buttonIndex < 3){
buttonIndex += 1;
}
if(buttonIndex == _pageImages.count){
//Navigate Outside Pageview controller
}else{
if (buttonIndex ==3) {
[_nextBtn setTitle:@"Begin" forState:UIControlStateNormal];
}
_backButton.hidden = NO;
PageContentViewController *startingViewController = [self viewControllerAtIndex:buttonIndex];
NSArray *viewControllers = @[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
}
}
//BUTTON INDEX & MAX COUNT
-(NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController{
return [self.pageImages count];}
-(NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController{
return buttonIndex;}
- (void)moveToPage {
NSUInteger pageIndex = ((ContentViewController *) [self.pageViewController.viewControllers objectAtIndex:0]).pageIndex;
pageIndex++;
ContentViewController *viewController = [self viewControllerAtIndex:pageIndex];
if (viewController == nil) {
return;
}
[self.pageViewController setViewControllers:@[viewController] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
}
//이 메서드를 호출
[self moveToPage];
나는 그것이 작동하기를 바랍니다 :)
단일 페이지의 경우 @Jack Humphries의 답변을 편집했습니다.
-(void)viewDidLoad
{
counter = 0;
}
-(IBAction)buttonClick:(id)sender
{
counter++;
DataViewController *secondVC = [self.modelController viewControllerAtIndex:counter storyboard:self.storyboard];
NSArray *viewControllers = nil;
viewControllers = [NSArray arrayWithObjects:secondVC, nil];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
}
@samwize가 지적했듯이 페이지 매김 방법은
setViewControllers:array
내가 한 방식은 다음과 같습니다. 데이터 원본과 대리인이 별도로 있습니다. 이 메소드를 호출하고 "다음"보기 만 변경할 수 있습니다. 이전에는 페이징 규칙을 적용해야합니다. 즉, 방향과 다음 컨트롤러를 확인해야합니다. 해당 메소드를 사용자 정의 데이터 소스와 함께 사용하면 표시하는 컨트롤러 배열이 변경되지 않습니다 (NSObject 서브 클래스에서 사용자 정의 배열을 사용하기 때문에).
이 방법은 자체 데이터 소스를 사용하여 특정 방향으로 새 뷰를 설정합니다. 정상적으로 스 와이프 할 때 표시되는 페이지를 계속 제어하기 때문입니다.
나는 어제부터 그것에 대해 노력하고 있으며 마침내 그것이 효과가있었습니다. 세 가지 다른 viewController가 자식보기로 있기 때문에 표준 템플릿을 완전히 사용할 수 없었습니다.
1 - rootViewController;
2 - model;
3 - viewControllers
3.1 - VC1;
3.2 - VC2;
3.3 - VC3.
Note: all of VCs has Storyboard ID.
첫 번째 VC에서만 트리거 버튼이 필요했기 때문에 pageViewController 및 model에 대해 하나의 속성을 추가했습니다.
#import <UIKit/UIKit.h>
#import "Model.h"
@interface VC1 : UIViewController
@property (nonatomic, strong) UIPageViewController *thePageViewController;
@property (nonatomic, strong) SeuTimePagesModel *theModel;
@end
스토리 보드와 pageViewController를 매개 변수로 전달하기 위해 모델의 init 메소드를 다시 작성 했으므로 VC1로 설정할 수 있습니다.
- (id)initWithStoryboard:(UIStoryboard *)storyboard
andPageViewController:(UIPageViewController *)controller
{
if (self = [super init])
{
VC1 *vc1 = [storyboard instantiateViewControllerWithIdentifier:@"VC1"];
vc1.pageViewController = controller;
vc1.model = self;
VC2 *vc2 = [storyboard instantiateViewControllerWithIdentifier:@"VC2"];
VC3 *vc3 = [storyboard instantiateViewControllerWithIdentifier:@"VC3"];
self.pageData = [[NSArray alloc] initWithObjects:vc1, vc2, vc3, nil];
}
return self;
}
마지막으로, VC1에 IBAction을 추가하여 pageViewController 메소드 setViewControllers : direction : animated : completion : 을 트리거했습니다 .
- (IBAction)go:(id)sender
{
VC2 *vc2 = [_model.pages objectAtIndex:1];
NSArray *viewControllers = @[vc2];
[_pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
}
참고 VC 색인을 찾을 필요가 없으며 버튼으로 두 번째 VC로 이동하지만 모든 색인을 얻는 것은 어렵지 않으며 자녀의 견해를 추적하지는 않습니다.
- (IBAction)selecionaSeuTime:(id)sender
{
NSUInteger index = [_model.pages indexOfObject:self];
index++;
VC2 *vc2 = [_model.pages objectAtIndex:1];
NSArray *viewControllers = @[vc2];
[_pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
}
도움이 되길 바랍니다.
UIPageViewControllerDataSource 메서드를 사용하는 솔루션은 다음과 같습니다 .
코드는 UIPageViewController 에서 현재 표시된 뷰 컨트롤러를 추적 합니다.
...
@property (nonatomic, strong) UIViewController *currentViewController;
@property (nonatomic, strong) UIViewController *nextViewController;
...
먼저 currentViewController 를 UIPageViewController에 대해 설정된 초기보기 컨트롤러로 초기화 하십시오 .
- (void) viewDidLoad {
[super viewDidLoad];
...
self.currentViewController = self.viewControllers[0];
...
[self.pageViewController setViewControllers: @[self.currentViewController] direction: dir animated: YES completion: nil];
}
그런 다음 UIPageViewControllerDelegate 메소드 에서 currentViewController 를 추적 하십시오 . pageViewController : willTransitionToViewControllers : 및 pageViewController : didFinishAnimating : previousViewControllers : transitionCompleted : .
- (nullable UIViewController *) pageViewController: (UIPageViewController *) pageViewController viewControllerBeforeViewController: (UIViewController *) viewController {
NSInteger idx = [self.viewControllers indexOfObject: viewController];
if (idx > 0) {
return self.viewControllers[idx - 1];
} else {
return nil;
}
}
- (nullable UIViewController *) pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController: (UIViewController *) viewController {
NSInteger idx = [self.viewControllers indexOfObject: viewController];
if (idx == NSNotFound) {
return nil;
} else {
if (idx + 1 < self.viewControllers.count) {
return self.viewControllers[idx + 1];
} else {
return nil;
}
}
}
- (void) pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers {
self.nextViewController = [pendingViewControllers firstObject];
}
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray<UIViewController *> *)previousViewControllers transitionCompleted:(BOOL)completed {
if (completed) {
self.currentViewController = self.nextViewController;
}
}
마지막으로, 선택한 방법 (아래 예에서 -(IBAction) onNext : (id) sender ))에서 UIPageViewControllerDataSouce 메소드 pageViewController : viewControllerBeforeViewController : , pageViewController : viewControllerAfterViewController : 를 사용하여 프로그래밍 방식으로 다음 또는 이전 컨트롤러로 전환 할 수 있습니다 . 다음 또는 이전보기 컨트롤러에서 [self.pageViewController setViewControllers : @ [vc] 방향 을 호출하여 탐색하십시오 . UIPageViewControllerNavigationDirectionForward 애니메이션 : YES 완료 : nil];
- (void) onNext {
UIViewController *vc = [self pageViewController: self.tutorialViewController viewControllerAfterViewController: self.currentViewController];
if (vc != nil) {
self.currentViewController = vc;
[self.tutorialViewController setViewControllers: @[vc] direction: UIPageViewControllerNavigationDirectionForward animated: YES completion: nil];
}
}
ViewController가 PageViewController에 내장되어 있으므로 다음과 같이하면됩니다.
Xamarin의 예제이지만 Swift 등과 기능적으로 유사합니다. 다음 코드는 페이지로 표시되는 ViewController 중 하나에서 Button Click 대리자에 있습니다.
var parent = ParentViewController as WelcomePageViewController;
var next = parent.DataSource.GetNextViewController(parent, this);
parent.SetViewControllers(new UIViewController[] { next }, UIPageViewControllerNavigationDirection.Forward, true, null);