I have a QuizViewController which extends UIViewController, UIPageControllerDelegate
, and a UIPageViewControllerDataSource
.
Inside 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?
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
PageViewController is the middle one in the storyboard.
PageViewController has the storyboard id as QuizPageViewController.
QuizViewController is the left one in the storyboard.
QuizViewController instantiates a PageViewController using the storyboard id QuizPageViewController
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 is the right most view in the Main.storyboard.
So if you see the 2 mockups, they are both QuizPageItems.
The first mockup should have a itemIndex of 0.
The second mockup should have itemIndex of 1.
let CurrentQuizPageItem = self.storyboard!.instantiateViewControllerWithIdentifier("QuizPageItem") as! QuizPageItem
CurrentQuizPageItem.itemIndex = itemIndex
Most of the answers I have received suggests solving it via the QuizViewController aka the left most view in my Main.storyboard.
However, the buttons are in the QuizPageItem and not accessible via the 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
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.
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/
UPDATE 2 I 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.
I assume there is a function in the QuizViewController that will trigger the page turning.
I am not sure what that function is.
These are the functions that I know will get triggered when the buttons are pressed.
I have the following inside the QuizPageItem class
@IBAction func pageBackButton(sender: AnyObject) {
}
@IBAction func pageNextButton(sender: AnyObject) {
}
However, they are not in the QuizViewController class but in the QuizPageItem class.
Am I supposed to put the setViewController method in these two functions inside QuizPageItem class?
And if so, how do I even access the QuizViewController instance from inside the QuizPageItem class?
UPDATE 3:
My file structure is
- QuizViewController.swift
- QuizPageItem.swift
The QuizViewController controls which QuizPageItem you see. A QuizPageItem represents a different view as designed by the mockup.
UPDATE4:
matt's answer helped me a lot with understanding this FirstResponder which I was totally unfamiliar with in the first place.
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
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)
}
}