web-dev-qa-db-ja.com

Swift iOS:ボタンを使用して次のページをトリガーする方法

enter image description here

enter image description here

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
   }

私の質問は、次へと戻るボタンを正しく機能させるにはどうすればよいですか?

現在、ページはスワイプで変更できます。スワイプは使いたくない。次へと戻るボタンを使ってコントロールしたい。

[〜#〜]更新[〜#〜]

enter image description here

これはMain.storyboardにあります

PageViewControllerは、ストーリーボードの真ん中のものです。

PageViewControllerのストーリーボードIDはQuizPageViewControllerです。

QuizViewControllerは、ストーリーボードの左側にあります。

QuizViewControllerは、ストーリーボードIDQuizPageViewControllerを使用してPageViewControllerをインスタンス化します。

これはこのブロックによって行われます

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

このインスタンス化が発生すると、QuizPageItemのフロントページも作成されます。

QuizPageItemは、Main.storyboardの右端のビューです。

したがって、2つのモックアップが表示されている場合、それらは両方ともQuizPageItemsです。

最初のモックアップのitemIndexは0である必要があります。

2番目のモックアップのitemIndexは1である必要があります。

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

私が受け取った回答のほとんどは、QuizViewController、つまりMain.storyboardの左端のビューを介して解決することを提案しています。

ただし、ボタンはQuizPageItemにあり、QuizViewControllerからアクセスすることはできません。

Main.storyboardのさまざまなビューを配線する方法が正しいと仮定して、QuizPageItemの[戻る]/[次へ]ボタンを接続して、QuizViewControllerで制御されるページネーションを実行する方法を知りたい

同時に、Main.storyboardのさまざまなビューを配線している現在の方法が理想的ではない可能性を許容します。

もしそうなら、別の方法をアドバイスしてください。

これは、私が現在いる場所にたどり着くために従うチュートリアルです。

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

UPDATE 2私は主張していると見られていることをお詫びします。私は本当にこれを行う方法を学びたいです。私はいくつかの基本的な知識が不足していると確信しているので、マイケル・ドーターマンの答えを理解することができません。

QuizViewControllerには、ページめくりをトリガーする関数があると思います。

その機能が何なのかわかりません。

これらは、ボタンが押されたときにトリガーされると私が知っている関数です。

QuizPageItemクラス内に次のものがあります

 @IBAction func pageBackButton(sender: AnyObject) {

 }

 @IBAction func pageNextButton(sender: AnyObject) {
 }

ただし、これらはQuizViewControllerクラスではなく、QuizPageItemクラスにあります。

QuizPageItemクラス内のこれら2つの関数にsetViewControllerメソッドを配置することになっていますか?

もしそうなら、QuizPageItemクラス内からQuizViewControllerインスタンスにアクセスするにはどうすればよいですか?

更新3:

私のファイル構造は

  • QuizViewController.Swift
  • QuizPageItem.Swift

QuizViewControllerは、表示するQuizPageItemを制御します。 QuizPageItemは、モックアップによって設計された別のビューを表します。

UPDATE4:

マットの答えは、私が最初からまったくなじみのないこのFirstResponderを理解するのに大いに役立ちました。

それを実装しようとすると、このエラーに直面しました。

enter image description here

私はグーグルで回り、それを改善しようとしましたが無駄になりました。

私はこのエラーを引き起こし続けました。

添付されているのは、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)
    }
}
6
Kim Stacks

このスクリーンキャストが示すように、MichaelDautermannの答えは完全に正しいです。

enter image description here

表示されているのは、複数のページ(順序を確認できるように番号が付けられています)があり、各ページに[次へ]ボタンが含まれているページビューコントローラーです。次のページに移動するために[次へ]ボタンを繰り返し押しています。

あなたのプロジェクトと同様に、上のスクリーンキャストに示されている私のプロジェクトには、ViewController階層があります。

  • UITabBarController

  • ViewController

  • UIPageViewController

  • ページ(メインビューがあり、ラベルとボタンはそのサブビューです)

あなたの質問の核心は、ページビューコントローラーが次または前のページに移動する方法ではなく、すでに言われているように、単に_setViewControllers:..._ですが、ボタンがどのように通信するかということではないようです。ビューコントローラ階層を上に移動します。私の例では、これは、ページビュー内のボタンから、ページビューコントローラーを通過し、UIPageViewControllerを通過し、ViewControllerまでメッセージを送信することを意味します。ViewControllerは、UIPageViewControllerに何をすべきかを指示します。

私はそれを行うための多くの方法を考えることができます:

  • ボタンは、ViewControllerが登録されている通知を投稿します

  • ボタンは、ViewControllerがハンドラーを持っているnil-targetedアクションを送信します

  • ボタンはタブバーコントローラー(そのtabBarControllerプロパティ)にメッセージを送信し、タブバーコントローラーは現在選択されているビューにメッセージdownを送信しますコントローラー、ViewController

  • ボタンは、View Controller(ペン先またはストーリーボードでアクションとして構成されている)にメッセージを送信し、View Controllerである_parentViewController!.parentViewController!_にメッセージを送信します。

どちらが好きですか?個人的には、追加のコードを必要としないため、nil-targetedアクションが最も好きです。唯一のfunc pageNextButton()実装はViewControllerにあります。これは、ターゲットを絞らないアクションの美しさです。レスポンダーチェーンをたどり、受信者を探します自動的に。ページビューコントローラーとUIPageViewControllerには、この点に関するコードはまったくありません。

私はこれが_parentViewController!.parentViewController!_よりもはるかに好きです。後者は最終的にPage View Controllerが呼び出すことができるViewControllerのメソッドの名前を知っている必要があり、ViewControllerにキャストダウンする必要があるためです。これはあまり移植性がありません。私の意見では、ページビューコントローラにその環境についての知識が多すぎます。一方、ターゲットを絞らないアクションでは、送信者は実際のターゲットが誰であるかについて完全に不可知論者です。だから私はnil-targetアクションが一番好きで、通知が2番目に好きです。

16
matt

Swift 3.

非常に簡単な解決策はここにあります

UIViewControllerからページ(UIViewController)を変更するには、最初に親ViewControllerのインスタンス(UIPageViewControllerになります)を取得してから、現在のViewControllerを設定します

私の場合、「UserDetailsPVC」という名前のUIPageViewControllerがあり、次の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)
12
Rajat Jain

setViewControllers:direction:animated:completion: から プログラムでページをめくる

前または次のページのViewControllerを渡すだけで、すべての設定が完了します。

7

次を使用できます。

次のページ

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

前のページ

pageViewController.setViewControllers(startingViewControllers,
                                                direction: UIPageViewControllerNavigationDirection.Reverse,
                                                animated: true,
                                                completion: nil)
3
tuledev

この機能を使用できます:

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];
}
1
vien vu

Swift4.2あなたの望みを動かす非常に簡単な方法ViewController

//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)
0
Shakeel Ahmed