ios 是否可以在 UIPageViewController 中以编程方式翻页?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7208871/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 21:16:14  来源:igfitidea点击:

Is it possible to Turn page programmatically in UIPageViewController?

iosios5uikituipageviewcontroller

提问by RAGOpoR

Is it possible to turn page programmatically in UIPageViewController?

是否可以以编程方式翻页UIPageViewController

回答by samwize

Yes it is possible with the method:

是的,可以使用以下方法:

- (void)setViewControllers:(NSArray *)viewControllers 
                 direction:(UIPageViewControllerNavigationDirection)direction 
                  animated:(BOOL)animated 
                completion:(void (^)(BOOL finished))completion;`

That is the same method used for setting up the first view controller on the page. Similar, you can use it to go to other pages.

这与用于在页面上设置第一个视图控制器的方法相同。类似的,您可以使用它转到其他页面。

Wonder why viewControllersis an array, and not a single view controller?

想知道为什么viewControllers是一个数组,而不是单个视图控制器?

That's because a page view controller could have a "spine" (like in iBooks), displaying 2 pages of content at a time. If you display 1 page of content at a time, then just pass in a 1-element array.

那是因为页面视图控制器可以有一个“脊椎”(就像在 iBooks 中一样),一次显示 2 页内容。如果您一次显示 1 页内容,则只需传入一个 1 元素数组。

An example in Swift:

Swift 中的一个例子:

pageContainer.setViewControllers([displayThisViewController], direction: .Forward, animated: true, completion: nil)

回答by Joe

Since I needed this as well, I'll go into more detail on how to do this.

由于我也需要这个,我将更详细地介绍如何做到这一点。

Note: I assume you used the standard template form for generating your UIPageViewControllerstructure - which has both the modelViewControllerand dataViewControllercreated when you invoke it. If you don't understand what I wrote - go back and create a new project that uses the UIPageViewControlleras it's basis. You'll understand then.

注意:我假设您使用标准模板表单来生成您的UIPageViewController结构 -当您调用它时,它同时具有modelViewControllerdataViewControllercreated 。如果您不理解我写的内容 - 返回并创建一个使用 的新项目UIPageViewController作为它的基础。到时候你就明白了。

So, needing to flip to a particular page involves setting up the various pieces of the method listed above. For this exercise, I'm assuming that it's a landscape view with two views showing.Also, I implemented this as an IBAction so that it could be done from a button press or what not - it's just as easy to make it selector call and pass in the items needed.

因此,需要翻转到特定页面涉及设置上面列出的方法的各个部分。对于本练习,我假设它是一个显示两个视图横向视图。此外,我将其实现为一个 IBAction,以便它可以通过按下按钮或其他方式来完成 - 让它选择器调用并传入所需的项目同样容易。

So, for this example you need the two view controllers that will be displayed - and optionally, whether you're going forward in the book or backwards.

因此,对于此示例,您需要将显示的两个视图控制器 - 并且可以选择,无论您是在书中前进还是后退。

Note that I merely hard-coded where to go to pages 4 & 5 and use a forward slip. From here you can see that all you need to do is pass in the variables that will help you get these items...

请注意,我只是硬编码了第 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!  

}

回答by lekksi

Here's another code example for a single paged view. Implementation for viewControllerAtIndexis omitted here, it should return the correct view controller for the given index.

这是单个分页视图的另一个代码示例。这里省略了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];
}

Pages can be changed by calling

可以通过调用更改页面

[self changePage:UIPageViewControllerNavigationDirectionReverse];
[self changePage:UIPageViewControllerNavigationDirectionForward];

回答by wfbarksdale

I could totally be missing something here, but this solution seems a lot simpler than many others proposed.

我可能在这里完全遗漏了一些东西,但这个解决方案似乎比许多其他人提出的要简单得多。

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

回答by Graham

This code worked nicely for me, thanks.

这段代码对我来说很好用,谢谢。

This is what i did with it. Some methods for stepping forward or backwards and one for going directly to a particular page. Its for a 6 page document in portrait view. It will work ok if you paste it into the implementation of the RootController of the pageViewController template.

这就是我用它做的。一些用于向前或向后步进的方法以及一种用于直接进入特定页面的方法。它用于纵向视图中的 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];

    }

}

回答by Sam Bing

Swift 4:

斯威夫特 4:

I needed to go to the next controller when i tap next on a pagecontroller view controller and also update the pageControl index, so this was the best and most straightforward solution for me:

当我在 pagecontroller 视图控制器上点击 next 并更新 pageControl 索引时,我需要转到下一个控制器,所以这对我来说是最好和最直接的解决方案:

let pageController = self.parent as! PageViewController

pageController.setViewControllers([parentVC.orderedViewControllers[1]], direction: .forward, animated: true, completion: nil)

pageController.pageControl.currentPage = 1

回答by JakubKnejzlik

What about using methods from dataSource?

使用 dataSource 中的方法怎么样?

UIViewController *controller = [pageViewController.dataSource pageViewController:self.pageViewController viewControllerAfterViewController:pageViewController.viewControllers.firstObject];
[pageViewController setViewControllers:@[controller] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];

Analogically for backward.

比喻为落后。

回答by King-Wizard

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

}

回答by noRema

However using this 'self.pageViewController setViewControllers' method call does not call 'viewDidDissapear' on the viewController for the page that has been turned away, whereas manually turning a page does call viewDidDissapear on the turned away page. I believe this is the cause of my crash

然而,使用这个'self.pageViewController setViewControllers' 方法调用不会在viewController 上为被拒绝的页面调用'viewDidDissapear',而手动翻页会在被拒绝的页面上调用viewDidDissapear。我相信这是我崩溃的原因

"The number of view controllers provided (0) doesn't match the number required (1) for the requested transition"

“提供的视图控制器数量 (0) 与请求转换所需的数量 (1) 不匹配”

回答by tuliomir

I also needed a button to navigate left on a PageViewController, one that should do exactly what you would expect from the swipe motion.

我还需要一个按钮在 PageViewController 上向左导航,该按钮应该完全符合您对滑动动作的期望。

Since I had a few rules already in place inside "pageViewController:viewControllerBeforeViewController" for dealing with the natural swipe navigation, I wanted the button to re-use all that code, and simply could not afford to use specific indexesto reach pages as the previous answers did. So, I had to take an alternate solution.

由于我已经在“ pageViewController:viewControllerBeforeViewController”中制定了一些规则来处理自然滑动导航,我希望按钮重新使用所有代码,并且根本无法像以前一样使用特定索引来访问页面答案是。所以,我不得不采取替代解决方案。

Please note that the following code is for a Page View Controller that is a property inside my custom ViewController, and has its spine set to mid.

请注意,以下代码用于页面视图控制器,它是我的自定义 ViewController 中的一个属性,其脊椎设置为 mid。

Here is the code I wrote for my Navigate Left button:

这是我为“向左导航”按钮编写的代码:

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

You can do something very similar to make a right navigation button from here.

你可以做一些非常类似的事情来从这里制作一个正确的导航按钮。