Swift iOS:如何使用按钮触发下一页 [英] Swift iOS: how to trigger next page using buttons

查看:177
本文介绍了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 {
让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 {
让CurrentQuizPageItem = self.storyboard!.instantiateViewControllerWithIdentifier(QuizPageItem)为! QuizPageItem
CurrentQuizPageItem.itemIndex = itemIndex
CurrentQuizPageItem.thisPageInfo = pageInfo [itemIndex]
return CurrentQuizPageItem
}

return nil
}

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

让CurrentQuizPageItem = viewController为!如果CurrentQuizPageItem.itemIndex> QuizPageItem

0 {
返回getItemController(CurrentQuizPageItem.itemIndex - 1)
}

返回nil
}

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

让CurrentQuizPageItem = viewController为! QuizPageItem

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

return nil
}

我的问题是如何让下一个和后一个按钮正常工作?



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



更新



< a href =https://i.stack.imgur.com/va0G0.png =nofollow noreferrer>



这是在Main.storyboard上



PageViewController是故事板中的中间一个。



PageViewController的故事板ID为 QuizPageViewController



QuizViewController是故事板中的左侧。



QuizViewController使用storyboard id实例化一个PageViewController QuizPageViewController



由此块完成

 让pageController = self.storyboard!.instantiateViewControllerWithIdentifier(QuizPageViewController )作为! UIPageViewController 
pageController.dataSource = self

当这个实例化发生时,它还会创建首页对于QuizPageItem。



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



所以,如果你看到2个模型,它们都是QuizPageItems。



第一个模型应该有一个itemIndex为0。



第二个模型应该有itemIndex为1.

 让CurrentQuizPageItem = self.storyboard!.instantiateViewControllerWithIdentifier(QuizPageItem)为! QuizPageItem 
CurrentQuizPageItem.itemIndex = itemIndex

我收到的大部分答案建议通过 QuizViewController 又是我Main.storyboard中最左边的视图。



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



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



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



如果是这样,请提供另一种方式。



这是我按照的教程到达目前的位置。





我已经google了一下,我有试图纠正它无济于事。



我一直在触发此错误。



附件是代码片段 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 ,制药,农业,
电信,制造业,财务,银行,
零售,旅行,航空公司,旅游]

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

super.init(nibName:nil,bundle:nil)
}
必需init?(编码器aDecoder:NSCoder){
fatalError(init(编码器:)尚未实现)
}

覆盖func viewDidLoad(){
super.viewDidLoad()

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

if thisPageInfo [0] ==Welcome{
createCheckboxes()
pageProgressView.setProgress(0.33,animated:true)
}否则如果thisPageInfo [0] ==太棒了! {
createSlider()
pageProgressView.setProgress(0.67,animated:true)
}否则如果thisPageInfo [0] ==几乎那里......{
createSlider()
pageProgressView.setProgress(0.95,animated:true)
}
}

覆盖func viewDidAppear(动画:Bool){
super.viewDidAppear(动画) )
}
覆盖func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
//处置可以重新创建的任何资源。
}

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()

如果计数器%2 == 0 {
frame.origin.x + = fWidth
}否则{
frame .origin.x - = fWidth
frame.origin.y + = frame.size.height
contentSize.size.height + = frame.size.height
}

checkbox.titleLabel?.adjustsFontSizeToFitWidth = true
pageAnswerView.addSub view(复选框)
}
}

func didSelectCheckbox(状态:Bool,标识符:Int,title:String){
print(checkbox'\(标题)'有状态\(状态))
}

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 =强烈避免
leftlabel.sizeToFit()
pageAnswerView.addSubview(leftlabel)

let rightlabel = UILabel(frame:CGRectMake(0,40,0,0))
righ tlabel.text =强烈偏好
rightlabel.sizeToFit()
rightlabel.frame.origin.x = slider.frame.width - rightlabel.frame.width
pageAnswerView.addSubview(rightlabel)
}
}


解决方案

迈克尔Dautermann的回答是完全正确的,因为这个截屏视频显示:





您所看到的是一个包含多个页面的页面视图控制器(编号以便您可以查看订单),每个页面都包含一个下一步按钮,并且我反复按下一步按钮导航到下一页。 / p>

与您的一样,我的项目(如上面的截屏视频所示)具有视图控制器层次结构:




  • UITabBarController


  • ViewController


  • U IPageViewController


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




问题的核心似乎不是什么方法导致页面视图控制器导航到其下一页或上一页 - 正如您已经被告知的那样,只是 setViewControllers:... - 但按钮如何与视图控制器层次结构进行通信。在我的例子中,这意味着从Page的视图中的按钮发送消息,经过Page视图控制器,经过UIPageViewController,然后到ViewController,然后告诉UIPageViewController做什么。



我可以想到很多方法:




  • 该按钮发布ViewController的通知已注册


  • 该按钮发送一个nif-targeted动作,ViewController有一个处理程序


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


  • 该按钮向其视图控制器发送消息(在nib或storyboard中配置为动作),该消息向其 parentViewController!.parentViewController!,这是ViewController。




哪个呢 我更喜欢?就个人而言,我最喜欢没有针对性的动作,因为它不需要额外的代码。唯一的 func pageNextButton()实现在ViewController中。这是一个没有针对性的行动之美:它走上响应者链,寻找收件人,自动。在这方面,页面视图控制器和UIPageViewController完全没有代码。



我比 parentViewController更好!.parentViewController!,因为后者最终要求Page视图控制器知道它可以调用的ViewController中的方法名称,并且它必须转换为ViewController - 它不是非常便携并且给出了Page view controller在我看来,对环境的了解太多了。另一方面,如果没有针对性的行动,发送者完全不了解实际目标将会是谁!所以我最喜欢nil-target动作,并且通知次之。


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)
    }
}

解决方案

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

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.

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)

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.

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 down to 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.

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.

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.

这篇关于Swift iOS:如何使用按钮触发下一页的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆