是否可以在UIPageViewController
?
答案 0 :(得分:219)
是的,可以使用以下方法:
- (void)setViewControllers:(NSArray *)viewControllers
direction:(UIPageViewControllerNavigationDirection)direction
animated:(BOOL)animated
completion:(void (^)(BOOL finished))completion;`
这与在页面上设置第一个视图控制器的方法相同。类似的,你可以用它来转到其他页面。
不知道为什么viewControllers
是一个数组,而不是一个视图控制器?
这是因为页面视图控制器可以有一个“书脊”(就像在iBooks中一样),一次显示2页内容。如果您一次显示1页内容,则只需传入1个元素的数组。
Swift中的一个例子:
pageContainer.setViewControllers([displayThisViewController], direction: .Forward, animated: true, completion: nil)
答案 1 :(得分:35)
由于我也需要这个,我会详细介绍如何做到这一点。
注意:我假设您使用标准模板表单来生成UIPageViewController
结构 - 在您调用它时同时创建了modelViewController
和dataViewController
。如果您不理解我写的内容 - 请返回并创建一个使用UIPageViewController
作为基础的新项目。那你就明白了。
因此,需要翻转到特定页面涉及设置上面列出的方法的各个部分。在本练习中,我假设它是一个横向视图,其中显示了两个视图。此外,我将其实现为IBAction,以便可以通过按钮按下或不按下 - 它就像很容易进行选择器调用并传递所需的项目。
因此,对于此示例,您需要显示两个视图控制器 - 并且可选地,无论您是在书中还是向后推进。
请注意,我只是硬编码到第4页和第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!
}
答案 2 :(得分:27)
这是单页分页视图的另一个代码示例。这里省略了对 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];
答案 3 :(得分:14)
这段代码很适合我,谢谢。
这就是我用它做的。一些向前或向后步进的方法和一个直接进入特定页面的方法。它是纵向视图中的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 :(得分:14)
我完全可以在这里遗漏一些东西,但这个解决方案似乎比许多其他人提出的要简单得多。
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)
}
}
}
}
答案 5 :(得分:6)
Swift 4:
当我在页面控制器视图控制器上点击下一个并且还更新pageControl索引时,我需要转到下一个控制器,所以这对我来说是的最佳和最直接的解决方案:
let pageController = self.parent as! PageViewController
pageController.setViewControllers([parentVC.orderedViewControllers[1]], direction: .forward, animated: true, completion: nil)
pageController.pageControl.currentPage = 1
答案 6 :(得分:2)
在 Swift :
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
}
}
}
答案 7 :(得分:1)
然而,使用此'self.pageViewController setViewControllers'方法调用不会在viewController上为已被拒绝的页面调用'viewDidDissapear',而手动翻页则会在被拒绝的页面上调用viewDidDissapear。我相信这是我崩溃的原因
“提供的视图控制器数量(0)与请求的转换所需的数量(1)不匹配”
答案 8 :(得分:1)
我还需要一个按钮在PageViewController上向左导航,这个按钮应该完全按照滑动动作的要求进行导航。
由于我在“ pageViewController:viewControllerBeforeViewController ”中已经有一些规则用于处理自然滑动导航,我希望按钮能够重复使用所有代码,只需无法使用特定索引来覆盖之前的答案。所以,我不得不采取另一种解决方案。
请注意,以下代码适用于页面视图控制器,它是我的自定义ViewController中的属性,其主干设置为mid。
以下是我为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];
}
}
你可以做一些非常相似的事情,从这里做一个正确的导航按钮。
答案 9 :(得分:1)
对于单页,我刚刚编辑了@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];
}
答案 10 :(得分:1)
如果,如果PAGE CONTROL指示当前页面是O&amp;&amp;您希望页面通过滚动和放大来导航通过单击Page ViewController中的自定义按钮,下面的内容可能会有所帮助。
{ id: [ 1, 2, 3 ],
'Sepal.Length': [ 5.1, 4.9, 4.7 ],
'Sepal.Width': [ 3.5, 3, 3.2 ],
'Petal.Length': [ 1.4, 1.4, 1.3 ],
'Petal.Width': [ 0.2, 0.2, 0.2 ],
Species: [ 'setosa', 'setosa', 'setosa' ] }
//当用户滚动到下一页
时,委托调用viewControllerAfterViewController//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];
}
}
- (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];
}
答案 11 :(得分:1)
- (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];
我希望它有效:)
答案 12 :(得分:0)
正如@samwize指出的那样,分页的方式是使用
setViewControllers:array
这就是我做的方式: 我有我的数据源和委托分开。你可以调用这个方法,只改变&#34; next&#34;视图。以前,您必须应用分页规则。 也就是说,你必须检查方向和下一个控制器。如果将该方法与自定义数据源一起使用,那么您显示的控制器阵列将不会发生变化(因为您将在NSObject子类上使用自定义数组)。
使用您自己的数据源,该方法只是设置一个新视图(具有特定方向)。因为您仍然可以控制正常滑动时显示的页面。
答案 13 :(得分:0)
我从昨天开始研究它,我终于做到了。我无法完全使用标准模板,因为我有三个不同的viewControllers作为子视图:
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
我重写了模型的init方法,将storyboard和pageViewController作为参数传递,所以我可以将它们设置为我的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];
}
我希望它可以帮到你!
答案 14 :(得分:0)
这是使用 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)发件人),您可以使用以编程方式切换到下一个或上一个控制器UIPageViewControllerDataSouce 方法 pageViewController:viewControllerBeforeViewController:, pageViewController:viewControllerAfterViewController 来获取下一个或上一个视图控制器并通过调用 [self.pageViewController setViewControllers:@ [vc]方向:UIPageViewControllerNavigationDirectionForward动画:是完成:无];
- (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];
}
}
答案 15 :(得分:0)
由于ViewControllers嵌入在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);