J'ai un QuizViewController qui étend UIViewController , UIPageControllerDelegate
et une UIPageViewControllerDataSource
.
À l'intérieur 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
}
Ma question est comment puis-je obtenir les boutons suivant et arrière pour fonctionner correctement?
À l'heure actuelle, les pages peuvent être modifiées par balayage. Je ne veux pas utiliser le glissement. Je veux contrôler en utilisant les boutons suivant et précédent.
UPDATE
C'est sur le tableau principal
PageViewController est celui du milieu dans le storyboard.
PageViewController a l'ID de storyboard sous la forme QuizPageViewController .
QuizViewController est celui de gauche dans le storyboard.
QuizViewController instancie un PageViewController à l'aide de l'ID de storyboard QuizPageViewController
qui est fait par ce bloc
let pageController = self.storyboard!.instantiateViewControllerWithIdentifier("QuizPageViewController") as! UIPageViewController
pageController.dataSource = self
Lorsque cette instanciation se produit, elle crée également la page de couverture pour QuizPageItem.
QuizPageItem est la vue la plus à droite du tableau principal.
Donc, si vous voyez les 2 maquettes, il s’agit de QuizPageItems.
La première maquette doit avoir un itemIndex de 0.
La deuxième maquette devrait avoir itemIndex de 1.
let CurrentQuizPageItem = self.storyboard!.instantiateViewControllerWithIdentifier("QuizPageItem") as! QuizPageItem
CurrentQuizPageItem.itemIndex = itemIndex
La plupart des réponses que j'ai reçues suggèrent de résoudre le problème via la vue QuizViewController aka la vue la plus à gauche de mon tableau principal.
Cependant, les boutons se trouvent dans QuizPageItem et ne sont pas accessibles via QuizViewController.
Je souhaite savoir comment connecter les boutons Précédent/Suivant dans QuizPageItem pour exécuter la pagination contrôlée dans QuizViewController en supposant que les différentes vues de Main.storyboard soient câblées de manière appropriée
En même temps, j'autorise la possibilité que la manière actuelle de câbler les différentes vues dans le tableau principal ne soit pas idéale.
Si tel est le cas, veuillez indiquer un autre moyen.
C’est le tutoriel que je suis pour arriver là où je suis actuellement.
http://shrikar.com/ios-Swift-tutorial-uipageviewcontroller-as-user-onboarding-tool/
UPDATE 2 Je m'excuse de ce que je suis considéré comme argumentant. Je veux vraiment apprendre à faire cela. Je suis à peu près sûr que je manque de connaissances fondamentales, donc je suis incapable de comprendre la réponse de Michael Dautermann.
Je suppose qu'il existe une fonction dans QuizViewController qui déclenchera le changement de page.
Je ne suis pas sûr de ce que cette fonction est.
Celles-ci sont les fonctions que je sais que va se déclencher lorsque vous appuyez sur les boutons.
J'ai les éléments suivants dans la classe QuizPageItem
@IBAction func pageBackButton(sender: AnyObject) {
}
@IBAction func pageNextButton(sender: AnyObject) {
}
Cependant, ils ne font pas partie de la classe QuizViewController, mais de la classe QuizPageItem.
Suis-je censé mettre la méthode setViewController dans ces deux fonctions dans la classe QuizPageItem?
Et si oui, comment puis-je même accéder à l'instance QuizViewController à partir de la classe QuizPageItem?
UPDATE 3:
Ma structure de fichier est
Le QuizViewController contrôle le QuizPageItem que vous voyez. Un QuizPageItem représente une vue différente telle que conçue par la maquette.
UPDATE4:
la réponse de matt m'a beaucoup aidé à comprendre ce FirstResponder avec lequel je ne connaissais absolument rien du tout.
Lorsque j'ai essayé de l'implémenter, j'ai été confronté à cette erreur.
J'ai cherché sur Google et j'ai essayé d'y remédier en vain.
J'ai continué à déclencher cette erreur.
Ci-joint l'extrait de code pour le 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)
}
}
La réponse de Michael Dautermann est tout à fait correcte, comme le montre ce screencast:
Ce que vous voyez est un contrôleur de visualisation de page avec plusieurs pages (numérotées pour que vous puissiez voir la commande), chaque page contenant un bouton Suivant. J'appuie plusieurs fois sur le bouton Suivant pour passer à la page suivante.
Comme le vôtre, mon projet, illustré dans la capture d'écran ci-dessus, a une hiérarchie de contrôleur de vue:
UITabBarController
ViewController
UIPageViewController
Page (qui a une vue principale, et l'étiquette et les boutons sont des sous-vues de celle-ci)
Il semble que le cœur de votre question ne soit pas tant sur la méthode qui oblige un contrôleur de vue de page à accéder à sa page suivante ou précédente - cela, comme on vous l'a déjà dit, est simplement setViewControllers:...
- mais à la façon dont le bouton communique avec le contrôleur de vue hiérarchie. Dans mon exemple, cela signifie qu’il faut envoyer un message à partir du bouton situé dans la vue Page, au-delà du contrôleur de vue de Page, du contrôle UIPageViewController et jusqu’au ViewController, qui indique ensuite à UIPageViewController quoi faire.
Je peux penser à de nombreuses façons de le faire:
Le bouton publie une notification pour laquelle ViewController est enregistré.
Le bouton envoie une action non ciblée pour laquelle ViewController a un gestionnaire.
Le bouton envoie un message au contrôleur de la barre d’onglet (propriété tabBarController
), qui envoie ensuite un message down à son contrôleur de vue actuellement sélectionné, le ViewController.
Le bouton envoie un message à son contrôleur de vue (configuré dans le nib ou le storyboard en tant qu'action), qui envoie un message à son parentViewController!.parentViewController!
, qui est ViewController.
Lequel est-ce que je préfère? Personnellement, ce qui me plaît le plus, c’est l’action ciblée sur zéro, car elle ne nécessite aucun code supplémentaire. La seule implémentation de func pageNextButton()
est dans ViewController. C'est la beauté d'une action non ciblée: elle parcourt la chaîne de répondeurs, recherchant un destinataire, automatiquement . Le contrôleur de vue de page et le UIPageViewController n'ont aucun code à cet égard.
J'aime beaucoup mieux cela que parentViewController!.parentViewController!
, car ce dernier exige en fin de compte que le contrôleur de vue de page connaisse le nom d'une méthode dans ViewController qu'il peut appeler, et il doit afficher un ViewController - qui n'est pas très portable et donne la page. Voir contrôleur trop de connaissances sur son environnement, à mon avis. En revanche, avec une action sans cible, l'expéditeur est totalement agnostique quant à savoir qui sera la cible réelle! Je préfère donc les actions nulles et ciblées, ainsi que les notifications.
Swift 3.0
La solution très simple est ici
Pour changer de page (UIViewController) à partir d'un UIViewController, commencez par obtenir l'instance de ViewController parent (qui sera UIPageViewController), puis définissez son ViewController actuel.
Dans mon cas, j'ai un UIPageViewController nommé "UserDetailsPVC" et il contient 4 pages (UIViewControllers) qui sont comme suit
PageOneVC:UIViewController
PageTwoVC:UIViewController
PageThreeVC:UIViewController
PageFourVC:UIViewController
Dans le UIPageViewController permet de définir un tableau de pages
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")
]
Maintenant, pour changer la page de UIPageViewController à partir de l’un des UIViewController
// 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)
Vous pouvez utiliser setViewControllers:direction:animated:completion:
to tourner vos pages par programmation .
Passez simplement le contrôleur de vue de la page précédente ou suivante et vous devriez être prêt.
Vous pouvez utiliser:
Pour la page suivante
pageViewController.setViewControllers(startingViewControllers,
direction: UIPageViewControllerNavigationDirection.Forward,
animated: true,
completion: nil)
Pour la page précédente
pageViewController.setViewControllers(startingViewControllers,
direction: UIPageViewControllerNavigationDirection.Reverse,
animated: true,
completion: nil)
Vous pouvez utiliser cette fonction:
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];
}
Swift 4.2 Un moyen très facile de réaliser vos souhaits View Controller
//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)