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
Swift iOS: how to trigger next page using buttons
提问by Kim Stacks
I have a QuizViewControllerwhich extends UIViewController, UIPageControllerDelegate
, and a UIPageViewControllerDataSource
.
我有一个QuizViewController延伸的UIViewController,UIPageControllerDelegate
和UIPageViewControllerDataSource
。
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
更新
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.
当我尝试实现它时,我遇到了这个错误。
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 的回答是完全正确的,如此截屏视频所示:
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
tabBarController
property), which then sends a message downto its currently selected view controller, the ViewControllerThe 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)