Swift iOS: как вызвать следующую страницу с помощью кнопок

введите описание изображения здесь

введите описание изображения здесь

У меня есть QuizViewController, который расширяет UIViewController, UIPageControllerDelegate и UIPageViewControllerDataSource.

Внутри 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
   }

Мой вопрос: как заставить кнопки «Далее» и «Назад» работать правильно?

Сейчас страницы можно менять свайпом. Я не хочу использовать свайп. Я хочу управлять с помощью кнопок «Далее» и «Назад».

ОБНОВЛЕНИЕ

введите описание изображения здесь

Это на Main.storyboard

PageViewController — средний в раскадровке.

PageViewController имеет идентификатор раскадровки как QuizPageViewController.

QuizViewController — левый в раскадровке.

QuizViewController создает экземпляр PageViewController, используя идентификатор раскадровки QuizPageViewController.

что делает этот блок

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

При создании этого экземпляра также создается главная страница для QuizPageItem.

QuizPageItem — самый правый вид в Main.storyboard.

Итак, если вы видите 2 макета, они оба являются QuizPageItems.

Первый макет должен иметь itemIndex равный 0.

Второй макет должен иметь itemIndex равный 1.

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

Большинство ответов, которые я получил, предлагают решить это с помощью QuizViewController, также известного как самое левое представление в моей Main.storyboard.

Однако кнопки находятся в QuizPageItem и недоступны через QuizViewController.

Я хочу знать, как подключить кнопки «Назад/Далее» в QuizPageItem для выполнения разбивки на страницы, которая управляется в QuizViewController, при условии, что способ подключения различных представлений в Main.storyboard правильный

В то же время я допускаю возможность того, что текущий способ подключения различных представлений в Main.storyboard не идеален.

Если да, то посоветуйте альтернативный способ.

Это руководство, которому я следую, чтобы добраться туда, где я сейчас нахожусь.

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

ОБНОВЛЕНИЕ 2 Приношу извинения за то, что я спорю. Я искренне хочу научиться этому. Я почти уверен, что мне не хватает некоторых фундаментальных знаний, поэтому я не могу понять ответ Майкла Даутерманна.

Я предполагаю, что в QuizViewController есть функция, которая запускает перелистывание страниц.

Я не уверен, что это за функция.

Я знаю, что эти функции будут запускаться при нажатии кнопок.

У меня есть следующее внутри класса QuizPageItem

 @IBAction func pageBackButton(sender: AnyObject) {

 }

 @IBAction func pageNextButton(sender: AnyObject) {
 }

Однако они находятся не в классе QuizViewController, а в классе QuizPageItem.

Должен ли я поместить метод setViewController в эти две функции внутри класса QuizPageItem?

И если да, то как мне вообще получить доступ к экземпляру QuizViewController из класса QuizPageItem?

ОБНОВЛЕНИЕ 3:

Моя файловая структура

  • QuizViewController.swift
  • QuizPageItem.swift

QuizViewController контролирует, какой QuizPageItem вы видите. QuizPageItem представляет другое представление, разработанное макетом.

ОБНОВЛЕНИЕ 4:

Ответ Мэтта очень помог мне понять этого FirstResponder, с которым я был совершенно незнаком.

Когда я попытался реализовать это, я столкнулся с этой ошибкой.

введите описание изображения здесь

Я гуглил и пытался исправить это безрезультатно.

Я продолжал вызывать эту ошибку.

Прилагается фрагмент кода для 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)
    }
}

person Kim Stacks    schedule 29.10.2015    source источник
comment
stackoverflow.com/questions/7208871/ Ответ @Yogesh может быть полезен   -  person Yogesh Lolusare    schedule 08.03.2017


Ответы (6)


Ответ Майкла Даутерманна совершенно правильный, как показывает этот скринкаст:

введите здесь описание изображения

То, что вы видите, — это контроллер представления страницы с несколькими страницами (пронумерованными, чтобы вы могли видеть порядок), каждая страница содержит кнопку «Далее», и я несколько раз нажимаю кнопку «Далее», чтобы перейти к следующей странице.

Как и ваш, мой проект, показанный на скринкасте выше, имеет иерархию контроллера представления:

  • UITabBarController

  • ViewController

  • UIPageViewController

  • Страница (которая имеет основное представление, а метка и кнопки являются его подвидами)

Похоже, что суть вашего вопроса заключается не столько в том, какой метод заставляет контроллер представления страницы переходить на следующую или предыдущую страницу — это, как вам уже сказали, просто setViewControllers:..., — но в том, как кнопка взаимодействует с контроллером представления. иерархия. В моем примере это означает отправку сообщения от кнопки внутри представления страницы, мимо контроллера представления страницы, мимо UIPageViewController и до ViewController, который затем сообщает UIPageViewController, что делать.

Я могу придумать множество способов сделать это:

  • Кнопка отправляет уведомление, для которого зарегистрирован ViewController

  • Кнопка отправляет действие с нулевым целевым значением, для которого у ViewController есть обработчик.

  • Кнопка отправляет сообщение контроллеру панели вкладок (его свойство tabBarController), который затем отправляет сообщение down выбранному в данный момент контроллеру представления, ViewController.

  • Кнопка отправляет сообщение своему контроллеру представления (настроенному в nib или раскадровке как действие), который отправляет сообщение своему parentViewController!.parentViewController!, который является ViewController.

Что я предпочитаю? Лично мне больше всего нравится действие с нулевой целью, потому что оно не требует дополнительного кода. Единственная реализация func pageNextButton() находится в ViewController. В этом прелесть действия с нулевой целью: оно проходит вверх по цепочке респондентов в поисках получателя автоматически. Контроллер представления страницы и UIPageViewController вообще не имеют кода в этом отношении.

Мне это нравится намного больше, чем parentViewController!.parentViewController!, потому что последнее требует, чтобы контроллер представления Page в конечном счете знал имя метода в ViewController, который он может вызывать, и должен приводить его к ViewController, что не очень переносимо и дает Page Контроллер представления слишком много знает о своем окружении, на мой взгляд. С другой стороны, при нулевом целевом действии отправитель совершенно не зависит от того, кто окажется фактической целью! Так что мне больше всего нравится действие с нулевым целевым значением, а уведомление — вторым.

person matt    schedule 01.11.2015
comment
Прошу прощения, что меня считают спорящим. Я искренне хочу научиться этому. Я почти уверен, что мне не хватает некоторых фундаментальных знаний, поэтому я не могу понять ответ Майкла Даутерманна. Я добавил больше информации к моему вопросу. Спасибо за попытку довести меня до момента «ага». - person Kim Stacks; 01.11.2015
comment
Ладно, так что же ты еще не знаешь? На ваш вопрос уже неоднократно был дан ответ. Кнопка в QuizPageItem сообщает QuizViewController (или QuizPageViewController), что она была нажата, и QuizViewController (или QuizPageViewController) переходит на следующую или предыдущую страницу соответственно, вызывая setViewControllers:..., как вам уже было сказано несколько раз. Поэтому вы должны сделать это и принять один из ответов. - person matt; 01.11.2015
comment
Слушай, я сделал свой скринкаст еще больше похожим на твои рисунки. Я делаю именно то, что вы описываете, и я делаю это именно так, как сказали Майкл Даутерманн и другие. Ответы, которые вы получили являются ответом. Какие еще доказательства вам нужны? - person matt; 01.11.2015
comment
Спасибо за ваш ответ. Мой дополнительный вопрос: как кнопка в QuizPageItem сообщает QuizViewController, что она была нажата? Насколько я могу судить, я знаю только, что функция @IBAction pageNextButton(sender: AnyObject) срабатывает при нажатии кнопки. И эта функция находится внутри QuizPageItem, а не внутри QuizViewController. Я действительно еще не грока этого. Приношу извинения за доставленное разочарование. - person Kim Stacks; 02.11.2015
comment
Очень хорошо, я добавил некоторые дальнейшие обсуждения. Если вы не понимаете цепочку респондеров и нулевые действия, возможно, вы захотите прочитать мою книгу: apeth.com/iOSBook/ch11.html#_nil_targeted_actions Если вы не знаете, что такое уведомления: apeth.com/iOSBook/ch13.html#_notifications_2 Если вы не знаете об parentViewController и иерархии контроллеров представлений, вам может понадобиться прочитать всю главу о контроллерах представлений: apeth.com/iOSBook/ch19.html - person matt; 02.11.2015
comment
Если вы все еще не поняли, я разместил для вас пример проекта на github: github.com/ mattneub/pageViewControllerUsingInternalButtons - person matt; 02.11.2015
comment
Спасибо. Ваш репозиторий на github помог мне сделать это лучше. Тем не менее, я столкнулся с проблемами, когда следовал методу нулевых действий, я продолжаю вызывать эту фатальную ошибку о неправильной инструкции внутри метода required init?(coder aDecoder: NSCoder) {. Я погуглил и попробовал другие средства, предложенные в других вопросах StackOverflow. Ни один из них не работал. Я оставил фрагмент кода в вопросе под обновлением 4. Что вы предлагаете? - person Kim Stacks; 03.11.2015
comment
Это совсем другое дело, @KimStacks. Пожалуйста, не возвращайтесь снова и снова, задавая новые вопросы в комментариях; это называется быть пиявкой на Stack Overflow. Если у вас есть новый вопрос, задайте новый вопрос! - person matt; 03.11.2015

Свифт 3.0

Очень простое решение здесь

Чтобы изменить страницу (UIViewController) из UIViewController, сначала получите экземпляр Parent ViewController (который будет UIPageViewController), а затем установите его текущий ViewController.

В моем случае у меня есть UIPageViewController с именем «UserDetailsPVC», и он содержит 4 страницы (UIViewControllers), которые выглядят следующим образом.

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

В 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")
]

Теперь, чтобы изменить страницу UIPageViewController с любого из 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)
person Rajat Jain    schedule 22.06.2017

Вы можете использовать setViewControllers:direction:animated:completion:, чтобы перевернуть ваши страницы программно.

Просто пропустите контроллер представления предыдущей или следующей страницы, и все будет готово.

person Michael Dautermann    schedule 29.10.2015
comment
Привет, я обновил вопрос. Я не мог использовать ваш ответ, потому что все они являются одним и тем же ViewController (QuizPageItem). Я не могу просто передать следующий контроллер представления. - person Kim Stacks; 01.11.2015
comment
@KimStacks Ответ на ваш вопрос получен. Чтобы программно перелистывать страницы, нужно сообщить контроллеру просмотра страниц setViewControllers:direction:animated:completion:. Вам нужно перестать спорить и начать слушать. Это не имеет ничего общего с тем, что кнопка находится внутри страницы внутри контроллера просмотра страницы. Вы все еще можете отправить сообщение. - person matt; 01.11.2015
comment
Прошу прощения, что меня считают спорящим. Я искренне хочу научиться этому. Я почти уверен, что мне не хватает некоторых фундаментальных знаний, поэтому я не могу понять ваш ответ. Я добавил больше информации к моему вопросу. Спасибо за попытку довести меня до момента «ага». - person Kim Stacks; 01.11.2015

Ты можешь использовать:

Для следующей страницы

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

Для предыдущей страницы

pageViewController.setViewControllers(startingViewControllers,
                                                direction: UIPageViewControllerNavigationDirection.Reverse,
                                                animated: true,
                                                completion: nil)
person tuledev    schedule 29.10.2015
comment
Привет, я обновил вопрос. Я не мог использовать ваш ответ, потому что кнопки находятся внутри QuizPageItem. Мой обновленный вопрос прольет больше света. - person Kim Stacks; 01.11.2015

Вы можете использовать эту функцию:

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];
}
person vien vu    schedule 29.10.2015
comment
Привет, я обновил вопрос. Я не мог использовать ваш ответ, потому что кнопки находятся внутри QuizPageItem. Мой обновленный вопрос прольет больше света. - person Kim Stacks; 01.11.2015

Swift 4.2 Очень простой способ перемещаться по вашему желанию 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)
person Shakeel Ahmed    schedule 02.03.2019