jjzjj

ios - swift iOS : how to trigger next page using buttons

coder 2023-09-04 原文

我有一个 QuizViewController,它扩展了 UIViewControllerUIPageControllerDelegate 和一个 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 是 Storyboard 中的中间部分。

PageViewController 的 Storyboard ID 为 QuizPageViewController

QuizViewController 是 Storyboard中左边的那个。

QuizViewController 使用 Storyboard ID QuizPageViewController 实例化一个 PageViewController

这是由这个 block 完成的

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

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

QuizPageItem 是 Main.storyboard 中最右边的 View 。

因此,如果您看到这 2 个模型,它们都是 QuizPageItems。

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

第二个模型的 itemIndex 应该为 1。

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

我收到的大部分答案都建议通过 QuizViewController 解决它,也就是我的 Main.storyboard 中最左边的 View 。

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

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

与此同时,我承认目前在 Main.storyboard 中连接各种 View 的方式并不理想。

如果是这样,请建议另一种方法。

这是我到达当前位置所遵循的教程。

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

更新 2 很抱歉我被认为是在争论。我真的很想学习如何做到这一点。我很确定我缺乏一些基础知识,因此我无法理解 Michael Dautermann 的回答。

我假设 QuizViewController 中有一个函数会触发翻页。

我不确定那个函数是什么。

这些是我知道按下按钮时触发的功能。

我在 QuizPageItem 类中有以下内容

 @IBAction func pageBackButton(sender: AnyObject) {

 }

 @IBAction func pageNextButton(sender: AnyObject) {
 }

但是,它们不在 QuizViewController 类中,而是在 QuizPageItem 类中。

我是否应该将 setViewController 方法放在 QuizPageItem 类中的这两个函数中?

如果是这样,我什至如何从 QuizPageItem 类内部访问 QuizViewController 实例?

更新 3:

我的文件结构是

  • QuizViewController.swift
  • QuizPageItem.swift

QuizViewController 控制您看到的 QuizPageItem。 QuizPageItem 表示模型设计的不同 View 。

更新4:

matt 的回答对我理解这个我一开始完全不熟悉的 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)
    }
}

最佳答案

Michael Dautermann 的回答是完全正确的,正如这个截屏视频所示:

您看到的是一个包含多个页面(已编号以便您可以看到顺序)的页面 View Controller ,每个页面都包含一个“下一步”按钮,我反复按下“下一步”按钮以导航到下一页。

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

  • UITabBarController

  • View Controller

  • UIPageViewController

  • 页面(有一个主视图,标签和按钮是它的 subview )

您的问题的核心似乎不是什么方法导致页面 View Controller 导航到其下一页或上一页 — 正如您已经被告知的那样,它只是 setViewControllers:... — 但是按钮如何向上传达 View Controller 层次结构。在我的示例中,这意味着从页面 View 内的按钮发送消息,经过页面 View Controller ,经过 UIPageViewController,直到 ViewController,然后它告诉 UIPageViewController 做什么。

我可以想出很多方法来做到这一点:

  • 该按钮发布一个通知,ViewController 已为其注册

  • 按钮发送一个 nil-targeted Action ,ViewController 有一个处理程序

  • 按钮向标签栏 Controller (它的 tabBarController 属性)发送一条消息,然后它向其当前选择的 View Controller 发送一条消息down, View Controller

  • 按钮向它的 View Controller 发送一条消息(在 nib 或 Storyboard中配置为一个 Action ),它向它的 parentViewController!.parentViewController! 发送一条消息,也就是 ViewController .

我更喜欢哪个?就个人而言,我最喜欢 nil-targeted Action ,因为它不需要额外的代码。唯一的 func pageNextButton() 实现在 ViewController 中。这就是无目标操作的美妙之处:它沿着响应者链向上移动,自动寻找接收者。页面 View Controller 和 UIPageViewController 在这方面根本没有代码。

我比 parentViewController!.parentViewController! 更喜欢这个,因为后者最终要求页面 View Controller 知道它可以调用的 ViewController 中的方法的名称,并且它必须转换一直到 ViewController——在我看来,它不是很便携,并且给了页面 View Controller 太多关于其环境的知识。另一方面,对于无目标操作,发送者完全不知道实际目标是谁!所以我最喜欢无目标操作,其次是通知。

关于ios - swift iOS : how to trigger next page using buttons,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33407672/

有关ios - swift iOS : how to trigger next page using buttons的更多相关文章

  1. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  2. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  3. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  4. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  5. ruby - 为 IO::popen 拯救 "command not found" - 2

    当我将IO::popen与不存在的命令一起使用时,我在屏幕上打印了一条错误消息:irb>IO.popen"fakefake"#=>#irb>(irb):1:commandnotfound:fakefake有什么方法可以捕获此错误,以便我可以在脚本中进行检查? 最佳答案 是:升级到ruby​​1.9。如果您在1.9中运行它,则会引发Errno::ENOENT,您将能够拯救它。(编辑)这是在1.8中的一种hackish方式:error=IO.pipe$stderr.reopenerror[1]pipe=IO.popen'qwe'#

  6. ruby - IO::EAGAINWaitReadable:资源暂时不可用 - 读取会阻塞 - 2

    当我尝试使用“套接字”库中的方法“read_nonblock”时出现以下错误IO::EAGAINWaitReadable:Resourcetemporarilyunavailable-readwouldblock但是当我通过终端上的IRB尝试时它工作正常如何让它读取缓冲区? 最佳答案 IgetthefollowingerrorwhenItrytousethemethod"read_nonblock"fromthe"socket"library当缓冲区中的数据未准备好时,这是预期的行为。由于异常IO::EAGAINWaitReadab

  7. ruby - 如何使用 ruby​​ fibers 避免阻塞 IO - 2

    我需要将目录中的一堆文件上传到S3。由于上传所需的90%以上的时间都花在了等待http请求完成上,所以我想以某种方式同时执行其中的几个。Fibers能帮我解决这个问题吗?它们被描述为解决此类问题的一种方法,但我想不出在http调用阻塞时我可以做任何工作的任何方法。有什么方法可以在没有线程的情况下解决这个问题? 最佳答案 我没有使用1.9中的纤程,但是1.8.6中的常规线程可以解决这个问题。尝试使用队列http://ruby-doc.org/stdlib/libdoc/thread/rdoc/classes/Queue.html查看文

  8. ruby - 如何从 ruby​​ 中的 IO 对象获取文件名 - 2

    在ruby中...我有一个由外部进程创建的IO对象,我需要从中获取文件名。然而我似乎只能得到文件描述符(3),这对我来说不是很有用。有没有办法从此对象获取文件名甚至获取文件对象?我正在从通知程序中获取IO对象。所以这也可能是获取文件路径的一种方式? 最佳答案 关于howtogetathefilenameinC也有类似的问题,我将在这里以ruby​​的方式给出这个问题的答案。在Linux中获取文件名假设io是您的IO对象。以下代码为您提供了文件名。File.readlink("/proc/self/fd/#{io.fileno}")例

  9. iOS快捷指令:执行Python脚本(利用iSH Shell) - 2

    文章目录前言核心逻辑配置iSH安装Python创建Python脚本配置启动文件测试效果快捷指令前言iOS快捷指令所能做的操作极为有限。假如快捷指令能运行Python程序,那么可操作空间就瞬间变大了。iSH是一款免费的iOS软件,它模拟了一个类似Linux的命令行解释器。我们将在iSH中运行Python程序,然后在快捷指令中获取Python程序的输出。核心逻辑我们用一个“获取当前日期”的Python程序作为演示(其实快捷指令中本身存在“获取当前日期”的操作,因而此需求可以不用Python,这里仅仅为了演示方便),核心代码如下。>>>importtime>>>time.strftime('%Y-%

  10. iOS适配Unity-2019 - 2

    iOS适配Unity-2019背景由于2019起,Unity的Xcode工程,更改了项目结构。Unity2018的结构:可以看Targets只有一个Unity-iPhone,Unity-iPhone直接依赖管理三方库。Unity2019以后:Targets多了一个UnityFramework,UnityFramework管理三方库,Unity-iPhone依赖于UnityFramwork。所以升级后,会有若干的问题,以下是对问题的解决方式。问题一错误描述error:exportArchive:Missingsigningidentifierat"/var/folders/fr//T/Xcode

随机推荐