Swift iOS:如何使用按钮触发下一页

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33407672/
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-31 08:08:21  来源:igfitidea点击:

Swift iOS: how to trigger next page using buttons

iosswiftuipageviewcontrollerpageviews

提问by Kim Stacks

enter image description here

在此处输入图片说明

enter image description here

在此处输入图片说明

I have a QuizViewControllerwhich extends UIViewController, UIPageControllerDelegate, and a UIPageViewControllerDataSource.

我有一个QuizViewController延伸的UIViewControllerUIPageControllerDelegateUIPageViewControllerDataSource

Inside QuizViewController.swift

QuizViewController.swift内部

private var pageViewController: UIPageViewController?

private func createPageViewController() {
       let pageController = self.storyboard!.instantiateViewControllerWithIdentifier("QuizPageViewController") as! UIPageViewController
       pageController.dataSource = self

       if pageInfo.count > 0 {
           let firstController = getItemController(0)!
           let startingViewControllers: NSArray = [firstController]
           pageController.setViewControllers(startingViewControllers as? [UIViewController], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
       }

       pageViewController = pageController
       addChildViewController(pageViewController!)
       self.view.addSubview(pageViewController!.view)
       pageViewController!.didMoveToParentViewController(self)
   }

   private func getItemController(itemIndex: Int) -> QuizPageItem? {
       if itemIndex < pageInfo.count {
           let CurrentQuizPageItem = self.storyboard!.instantiateViewControllerWithIdentifier("QuizPageItem") as! QuizPageItem
           CurrentQuizPageItem.itemIndex = itemIndex
           CurrentQuizPageItem.thisPageInfo = pageInfo[itemIndex]
           return CurrentQuizPageItem
       }

       return nil
   }

   /*
       PageView Delegates
   */
   func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {

       let CurrentQuizPageItem = viewController as! QuizPageItem

       if CurrentQuizPageItem.itemIndex > 0 {
           return getItemController(CurrentQuizPageItem.itemIndex - 1)
       }

       return nil
   }

   func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {

       let CurrentQuizPageItem = viewController as! QuizPageItem

       if CurrentQuizPageItem.itemIndex + 1 < pageInfo.count {
           return getItemController(CurrentQuizPageItem.itemIndex + 1)
       }

       return nil
   }

My question is how do I get the next and back buttons to work properly?

我的问题是如何让 next 和 back 按钮正常工作?

Right now the pages can be changed via swipe. I don't want to use swipe. I want to control using the next and back buttons.

现在可以通过滑动更改页面。我不想使用滑动。我想使用下一步和后退按钮进行控制。

UPDATE

更新

enter image description here

在此处输入图片说明

This is on the Main.storyboard

这是在 Main.storyboard 上

PageViewController is the middle one in the storyboard.

PageViewController 是故事板中的中间部分。

PageViewController has the storyboard id as QuizPageViewController.

PageViewController 的故事板 ID 为QuizPageViewController

QuizViewController is the left one in the storyboard.

QuizViewController 是故事板中的左侧。

QuizViewController instantiates a PageViewController using the storyboard id QuizPageViewController

QuizViewController 使用故事板 id QuizPageViewController实例化一个 PageViewController

which is done by this block

这是由这个块完成的

       let pageController = self.storyboard!.instantiateViewControllerWithIdentifier("QuizPageViewController") as! UIPageViewController
       pageController.dataSource = self

When this instantiation happens, it also creates the front page for the QuizPageItem.

当此实例化发生时,它还会为 QuizPageItem 创建首页。

QuizPageItem is the right most view in the Main.storyboard.

QuizPageItem 是 Main.storyboard 中最右侧的视图。

So if you see the 2 mockups, they are both QuizPageItems.

因此,如果您看到 2 个模型,它们都是 QuizPageItems。

The first mockup should have a itemIndex of 0.

第一个模型的 itemIndex 应为 0。

The second mockup should have itemIndex of 1.

第二个模型的 itemIndex 应该为 1。

       let CurrentQuizPageItem = self.storyboard!.instantiateViewControllerWithIdentifier("QuizPageItem") as! QuizPageItem
       CurrentQuizPageItem.itemIndex = itemIndex

Most of the answers I have received suggests solving it via the QuizViewControlleraka the left most view in my Main.storyboard.

我收到的大多数答案都建议通过QuizViewController也就是我的 Main.storyboard 中最左边的视图来解决它。

However, the buttons are in the QuizPageItem and not accessible via the QuizViewController.

但是,按钮位于 QuizPageItem 中,无法通过 QuizViewController 访问。

I want to know how I can connect the back/next buttons in the QuizPageItem to execute the pagination which is controlled in the QuizViewController assuming the way I am wiring up the various views in the Main.storyboard is correct

我想知道如何连接 QuizPageItem 中的后退/下一步按钮以执行在 QuizViewController 中控制的分页,假设我在 Main.storyboard 中连接各种视图的方式是正确的

At the same time, I allow the possibility that the current way I am wiring up the various views in the Main.storyboard is not ideal.

同时,我允许我在 Main.storyboard 中连接各种视图的当前方式不理想的可能性。

If so, please advise an alternative way.

如果是这样,请建议另一种方式。

This is the tutorial I follow to get to where I am currently at.

这是我遵循的教程,以达到我目前所在的位置。

http://shrikar.com/ios-swift-tutorial-uipageviewcontroller-as-user-onboarding-tool/

http://shrikar.com/ios-swift-tutorial-uipageviewcontroller-as-user-onboarding-tool/

UPDATE 2I apologise that I am seen as arguing. I genuinely want to learn how to do this. I am pretty sure I am lacking some fundamental knowledge hence I am unable to understand Michael Dautermann's answer.

更新 2我很抱歉我被认为是在争论。我真的很想学习如何做到这一点。我很确定我缺乏一些基本知识,因此我无法理解 Michael Dautermann 的回答。

I assume there is a function in the QuizViewController that will trigger the page turning.

我假设 QuizViewController 中有一个函数会触发翻页。

I am not sure what that function is.

我不确定那个功能是什么。

These are the functions that I know willget triggered when the buttons are pressed.

这些是我知道按下按钮时触发的功能。

I have the following inside the QuizPageItem class

我在 QuizPageItem 类中有以下内容

 @IBAction func pageBackButton(sender: AnyObject) {

 }

 @IBAction func pageNextButton(sender: AnyObject) {
 }

However, they are not in the QuizViewController class but in the QuizPageItem class.

但是,它们不在 QuizViewController 类中,而是在 QuizPageItem 类中。

Am I supposed to put the setViewController method in these two functions inside QuizPageItem class?

我应该将 setViewController 方法放在 QuizPageItem 类中的这两个函数中吗?

And if so, how do I even access the QuizViewController instance from inside the QuizPageItem class?

如果是这样,我什至如何从 QuizPageItem 类内部访问 QuizViewController 实例?

UPDATE 3:

更新 3:

My file structure is

我的文件结构是

  • QuizViewController.swift
  • QuizPageItem.swift
  • QuizViewController.swift
  • QuizPageItem.swift

The QuizViewController controls which QuizPageItem you see. A QuizPageItem represents a different view as designed by the mockup.

QuizViewController 控制您看到的 QuizPageItem。QuizPageItem 表示模型设计的不同视图。

UPDATE4:

更新4:

matt's answer helped me a lot with understanding this FirstResponder which I was totally unfamiliar with in the first place.

马特的回答对我理解这个 FirstResponder 有很大帮助,我一开始完全不熟悉它。

When I tried to implement it, I was faced with this error.

当我尝试实现它时,我遇到了这个错误。

enter image description here

在此处输入图片说明

I have googled around and I have tried to remedy it to no avail.

我用谷歌搜索,我试图补救它无济于事。

I kept triggering this error.

我一直触发这个错误。

Attached is the code snippet for the QuizViewPageItemController.swift

附上代码片段 QuizViewPageItemController.swift

import UIKit
class QuizPageItemViewController: UIViewController, CheckboxDelegate {

    @IBOutlet weak var pageHeadingLabel: UILabel!
    @IBOutlet weak var pageInstructionLabel: UILabel!
    @IBOutlet weak var pageProgressView: UIProgressView!
    @IBOutlet weak var pageQuestionLabel: UILabel!
    @IBOutlet weak var pageAnswerView: UIView!
    @IBOutlet weak var pageBackButton: UIButton!
    @IBOutlet weak var pageNextButton: UIButton!
    let pageNo: Int 
    let maxPageNo: Int
    let thisPageInfo: [String]

    let interestsList = [
        "Blue Chips", "Small Caps", "Pharmaceuticals", "Agriculture",
        "Telecommunications", "Manufacturing", "Finance", "Banks",
        "Retail", "Travel", "Airlines", "Tourism"]

    init(pageNo: Int, maxPageNo: Int, thisPageInfo: [String]) {
        self.pageNo = pageNo
        self.maxPageNo = maxPageNo
        self.thisPageInfo = thisPageInfo

        super.init(nibName: nil, bundle: nil)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.pageBackButton.hidden = pageNo == 0
        self.pageNextButton.hidden = pageNo == maxPageNo
        pageHeadingLabel.text = thisPageInfo[0]
        pageInstructionLabel.text = thisPageInfo[1]
        pageQuestionLabel.text = thisPageInfo[2]

        if thisPageInfo[0] == "Welcome" {
            createCheckboxes()
            pageProgressView.setProgress(0.33, animated: true)
        } else if thisPageInfo[0] == "Awesome!" {
            createSlider()
            pageProgressView.setProgress(0.67, animated: true)
        } else if thisPageInfo[0] == "Almost there..." {
            createSlider()
            pageProgressView.setProgress(0.95, animated: true)
        }
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func createCheckboxes() {
        let fWidth = (self.view.frame.width - 40) / 2
        var frame = CGRectMake(0, 0, fWidth, 40)
        var contentSize = CGRectMake(0, 0, self.view.frame.width - 40, 0)

        for (var counter = 0; counter < interestsList.count; counter++) {
            let checkbox = Checkbox(frame: frame, title: interestsList[counter], selected: false)
            checkbox.mDelegate = self
            checkbox.tag = counter
            checkbox.backgroundColor = UIColor.redColor()

            if counter % 2 == 0 {
                frame.origin.x += fWidth
            } else{
                frame.origin.x -= fWidth
                frame.origin.y += frame.size.height
                contentSize.size.height += frame.size.height
            }

            checkbox.titleLabel?.adjustsFontSizeToFitWidth = true
            pageAnswerView.addSubview(checkbox)
        }
    }

    func didSelectCheckbox(state: Bool, identifier: Int, title: String) {
        print("checkbox '\(title)' has state \(state)")
    }

    func createSlider() {
        let slider = UISlider(frame:CGRectMake(0, 20, self.view.frame.width - 40, 20))
        slider.minimumValue = 0
        slider.maximumValue = 10
        slider.continuous = true
        slider.tintColor = ChatQColours().chatQBlue
        slider.value = 5
        //        slider.addTarget(self, action: "sliderValueDidChange:", forControlEvents: .ValueChanged)
        pageAnswerView.addSubview(slider)

        let leftlabel = UILabel(frame: CGRectMake(0, 40, 0, 0))
        leftlabel.text = "Strongly Avoid"
        leftlabel.sizeToFit()
        pageAnswerView.addSubview(leftlabel)

        let rightlabel = UILabel(frame: CGRectMake(0, 40, 0, 0))
        rightlabel.text = "Strongly Prefer"
        rightlabel.sizeToFit()
        rightlabel.frame.origin.x = slider.frame.width - rightlabel.frame.width
        pageAnswerView.addSubview(rightlabel)
    }
}

回答by matt

Michael Dautermann's answer is perfectly correct, as this screencast shows:

Michael Dautermann 的回答是完全正确的,如此截屏视频所示:

enter image description here

在此处输入图片说明

What you're seeing is a page view controller with multiple pages (numbered so you can see the order), each page containing a Next button, and I'm repeatedly pressing the Next button to navigate to the next page.

你看到的是一个页面视图控制器,它有多个页面(编号以便你可以看到顺序),每个页面包含一个 Next 按钮,我反复按下 Next 按钮导航到下一页。

Like yours, my project, illustrated in the screencast above, has a view controller hierarchy:

和你的一样,我的项目,如上面的截屏视频所示,有一个视图控制器层次结构:

  • UITabBarController

  • ViewController

  • UIPageViewController

  • Page (which has a main view, and the label and buttons are subviews of that)

  • UITabBarController

  • 视图控制器

  • UIPageViewController

  • 页面(有一个主视图,标签和按钮是它的子视图)

It appears that the heart of your question is not so much what method causes a page view controller to navigate to its next or previous page — that, as you have already been told, is simply setViewControllers:...— but how the button communicates up the view controller hierarchy. In my example, that means sending a message from the button inside Page's view, past the Page view controller, past the UIPageViewController, and up to the ViewController, which then tells th UIPageViewController what to do.

看起来您的问题的核心不是什么方法导致页面视图控制器导航到其下一页或上一页 - 正如您已经被告知的那样,很简单setViewControllers:...- 而是按钮如何向上传递视图控制器层次结构. 在我的示例中,这意味着从 Page 视图内的按钮发送消息,经过 Page 视图控制器,经过 UIPageViewController,直到 ViewController,然后它告诉 UIPageViewController 做什么。

I can think of numerous ways to do that:

我可以想到很多方法来做到这一点:

  • The button posts a notification for which the ViewController is registered

  • The button sends a nil-targeted action for which the ViewController has a handler

  • The button sends a message to the tab bar controller (its tabBarControllerproperty), which then sends a message downto its currently selected view controller, the ViewController

  • The button sends a message to its view controller (configured in the nib or storyboard as an action), which sends a message to its parentViewController!.parentViewController!, which is the ViewController.

  • 该按钮发布了一个通知,其中注册了 ViewController

  • 按钮发送一个以 nil 为目标的动作,ViewController 有一个处理程序

  • 该按钮向选项卡栏控制器(其tabBarController属性)发送一条消息,然后将消息向下发送到其当前选定的视图控制器 ViewController

  • 按钮向它的视图控制器发送一条消息(在笔尖或故事板中配置为一个动作),它向它的 发送一条消息parentViewController!.parentViewController!,即 ViewController。

Which do I prefer? Personally, I like the nil-targeted action best, because it requires no extra code. The only func pageNextButton()implementation is in ViewController. That is beauty of a nil-targeted action: it walks up the responder chain, looking for a recipient, automatically. The Page view controller and the UIPageViewController have no code at all in this regard.

我更喜欢哪个?就个人而言,我最喜欢以 nil 为目标的操作,因为它不需要额外的代码。唯一的func pageNextButton()实现是在 ViewController 中。这就是无目标操作的美妙之处:它沿着响应者链向上走,自动寻找接收者。页面视图控制器和 UIPageViewController 在这方面根本没有代码。

I like this much better than parentViewController!.parentViewController!, because the latter requires ultimately that the Page view controller knows the name of a method in the ViewController that it can call, and it must cast down to a ViewController — which is not very portable and gives the Page view controller too much knowledge about its environment, in my opinion. With a nil-targeted action, on the other hand, the sender is totally agnostic about who the actual target will turn out to be! So I like nil-target action best, and notification second best.

我比 更喜欢这个parentViewController!.parentViewController!,因为后者最终要求页面视图控制器知道它可以调用的 ViewController 中的方法的名称,并且它必须转换为一个 ViewController——它不是很可移植并且提供页面视图在我看来,控制器对其环境了解太多。另一方面,对于无目标操作,发送者完全不知道实际目标是谁!所以我最喜欢零目标动作,其次是通知。

回答by Rajat Jain

Swift 3.0

斯威夫特 3.0

Very simple solution is here

非常简单的解决方案在这里

To change page (UIViewController) from a UIViewController, first get the instance of Parent ViewController (which will be UIPageViewController) and then set its current ViewController

要从 UIViewController 更改页面 (UIViewController),首先获取父 ViewController 的实例(将是 UIPageViewController),然后设置其当前的 ViewController

In my case I have a UIPageViewController named "UserDetailsPVC" and it contains 4 pages (UIViewControllers) which are as follows

就我而言,我有一个名为“UserDetailsPVC”的 UIPageViewController,它包含 4 个页面(UIViewControllers),如下所示

  PageOneVC:UIViewController
  PageTwoVC:UIViewController
  PageThreeVC:UIViewController
  PageFourVC:UIViewController

In the UIPageViewController lets define an array of pages

在 UIPageViewController 中让我们定义一个页面数组

 var pages:[UIViewController] = [
        UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PageOneVC"),
        UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PageTwoVC"),
        UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PageThreeVC"),
        UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PageFourVC")
]

Now to change page of UIPageViewController from any of the UIViewController

现在从任何 UIViewController 更改 UIPageViewController 的页面

    // get parent view controller
    let parentVC = self.parent as! UserDetailsPVC

    // change page of PageViewController
    parentVC.setViewControllers([parentVC.pages[1]], direction: .forward, animated: true, completion: nil)

回答by Michael Dautermann

You can use setViewControllers:direction:animated:completion:to turn your pages programatically.

您可以使用setViewControllers:direction:animated:completion:编程方式翻页

Just pass along the previous or next page's view controller and you should be all set.

只需传递上一页或下一页的视图控制器,您就应该准备就绪。

回答by tuledev

You can use:

您可以使用:

For next page

下一页

pageViewController.setViewControllers(startingViewControllers,
                                                direction: UIPageViewControllerNavigationDirection.Forward,
                                                animated: true,
                                                completion: nil)

For previous page

对于上一页

pageViewController.setViewControllers(startingViewControllers,
                                                direction: UIPageViewControllerNavigationDirection.Reverse,
                                                animated: true,
                                                completion: nil)

回答by vien vu

You can use this function:

您可以使用此功能:

func movePageToIndex(pageIndex NSInteger)->() {
    var viewControllers = []
    var direction : UIPageViewControllerNavigationDirection! 
    if (pageIndex < currentIndex) {
        direction = UIPageViewControllerNavigationDirection.Reverse
    } else {
        direction = UIPageViewControllerNavigationDirection.Forward
    }
    viewControllers = @[[self.getItemController(pageIndex)]]

    WEAKSELF weakSelf = self;
    self.pageViewController.setViewControllers:viewControllers direction:direction animated:false completion:nil];
}

回答by Shakeel Ahmed

Swift 4.2 Very easy way to move on your desire View Controller

Swift 4.2 非常简单的方法来移动你想要的视图控制器

//MARK:- Programatically move to Next Page or Previous Page
//Your Desire index in Your UIViewController Array
    let arr : [UIViewController] = [arrvc[1]] 
    pagecontroller.setViewControllers(arr,
                                    direction: UIPageViewController.NavigationDirection.reverse,
                                    animated: true,
                                    completion: nil)