web-dev-qa-db-ja.com

UIPageViewControllerとストーリーボード

ストーリーボードから具体的にUIPageViewControllerを構成しようとしています:

enter image description here

TutorialPageViewController.h

#import <UIKit/UIKit.h>
@interface TutorialPageViewController : UIPageViewController <UIPageViewControllerDelegate, UIPageViewControllerDataSource>
@end

TutorialPageViewController.m

#import "TutorialPageViewController.h"

@interface TutorialPageViewController ()
@property (assign, nonatomic) NSInteger index;
@end

@implementation TutorialPageViewController
{
    NSArray *myViewControllers;
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.delegate = self;
    self.dataSource = self;
    [self didMoveToParentViewController:self];
    UIStoryboard *tutorialStoryboard = [UIStoryboard storyboardWithName:@"TutorialStoryboard" bundle:[NSBundle mainBundle]];
    UIViewController *tuto1 = [tutorialStoryboard instantiateViewControllerWithIdentifier:@"TutorialPageViewController_1"];
    UIViewController *tuto2 = [tutorialStoryboard instantiateViewControllerWithIdentifier:@"TutorialPageViewController_2"];

    myViewControllers = @[tuto1, tuto2, tuto1, tuto2];
    self.index = 0;

    [self setViewControllers:@[tuto1] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
}

- (UIViewController *)viewControllerAtIndex:(NSUInteger)index {
    return myViewControllers[index];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {

    NSUInteger index = self.index;

    if (index == 0) { return nil; }

    // Decrease the index by 1 to return
    index--;
    return [self viewControllerAtIndex:index];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {

    NSUInteger index = self.index;
    index++;
    if (index > [myViewControllers count]) { return nil; }

    return [self viewControllerAtIndex:index];
}

- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController {
    // The number of items reflected in the page indicator.
    return [myViewControllers count];
}

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
    // The selected item reflected in the page indicator.
    return 0;
}

@end

問題は...

  • 最初のページは、ページインジケータと共に表示されます。スワイプしながら、
  • 2ページ目が正しく表示されます。
  • 遷移が終了するとすぐに、黒い画面が表示されます(ページインジケーターにページ番号2が正しく表示されます)。ユーザーの操作はもう利用できません。
43
Benjamin Toueg

2017年の回答..

最近では、これを行うのは非常に簡単です単にStoryboardを使用する

このような「全画面表示のスワイプチュートリアル」は、しばらくの間「intros」アプリとして人気があったため、IntroPagesの下のクラスを呼び出しました。

ステップ1、UIPageViewControllerであるコンテナービューを作成します。

IOSを初めて使用する場合、ここに コンテナビューチュートリアル があります。

(注:コンテナービューをUIPageViewControllerに変更する方法がわからない場合は、そのチュートリアルの"How to change ..."セクションまでスクロールします。

enter image description here

コンテナを作成できます任意の形状。他のコンテナビューと同様に、フルスクリーンでも、画面の一部でも、どのようなものでもかまいません。

ステップ2、

必要なもの-画像、テキスト、表、その他何でも可能な4つの簡単なView Controllerを作成します。 (例では紫色。)

four controllers

これらは単にストーリーボードに配置であり、何にもリンクしないでください。

ステップ3、4つのページのIDを設定する必要があります。 「id1」、「id2」、「id4」、「id4」で問題ありません。

set the IDs

ステップ4、コピーして貼り付けます! IntroPagesクラスは次のとおりです。

class IntroPages: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var pages = [UIViewController]()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self
        self.dataSource = self

        let p1: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "id1")
        let p2: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "id2")
        let p3: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "id3")

        // etc ...

        pages.append(p1)
        pages.append(p2)
        pages.append(p3)

        // etc ...

        setViewControllers([p1], direction: UIPageViewControllerNavigationDirection.forward, animated: false, completion: nil)
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController)-> UIViewController? {

        let cur = pages.index(of: viewController)!

        // if you prefer to NOT scroll circularly, simply add here:
        // if cur == 0 { return nil }

        let prev = abs((cur - 1) % pages.count)
        return pages[prev]

    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController)-> UIViewController? {

        let cur = pages.index(of: viewController)!

        // if you prefer to NOT scroll circularly, simply add here:
        // if cur == (pages.count - 1) { return nil }

        let nxt = abs((cur + 1) % pages.count)
        return pages[nxt]
    }

    func presentationIndex(for pageViewController: UIPageViewController)-> Int {
        return pages.count
    }
}

(コメントを見てください-必要に応じて、ループまたは線形ページングのいずれかのコードがあります。)

これですべてです。完了です。

ストーリーボードで遷移スタイルを設定するだけで、

enter image description here

もう一方ではなく「スクロール」が必要になる可能性が非常に高くなります。

62
Fattie

作業ページのスクロール(前方/後方)を見たい人向け

-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
     viewControllerBeforeViewController:(UIViewController *)viewController
  {
     NSUInteger currentIndex = [myViewControllers indexOfObject:viewController];
     // get the index of the current view controller on display

     if (currentIndex > 0)
     {
        return [myViewControllers objectAtIndex:currentIndex-1];
        // return the previous viewcontroller
     } else
     {
         return nil;
         // do nothing
     }
  }
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
 viewControllerAfterViewController:(UIViewController *)viewController
  {
     NSUInteger currentIndex = [myViewControllers indexOfObject:viewController];
     // get the index of the current view controller on display
     // check if we are at the end and decide if we need to present
     // the next viewcontroller
     if (currentIndex < [myViewControllers count]-1)
     {
        return [myViewControllers objectAtIndex:currentIndex+1];
        // return the next view controller
     } else
     {
        return nil;
        // do nothing
     }
  }

EditORによるこの優れた答えに追加するために、「ラウンドアンドアラウンド」ページングを好む場合に行うことは次のとおりです。EditORの同じテクニックを引き続き使用します。

-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
        viewControllerBeforeViewController:(UIViewController *)viewController
    {
    NSUInteger currentIndex = [myViewControllers indexOfObject:viewController];

    --currentIndex;
    currentIndex = currentIndex % (myViewControllers.count);
    return [myViewControllers objectAtIndex:currentIndex];
    }

-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
        viewControllerAfterViewController:(UIViewController *)viewController
    {
    NSUInteger currentIndex = [myViewControllers indexOfObject:viewController];

    ++currentIndex;
    currentIndex = currentIndex % (myViewControllers.count);
    return [myViewControllers objectAtIndex:currentIndex];
    } 
19
EditOR

拡張 Joe Blowの答え with Swift UIPageViewControllerクラスのコード:

import UIKit

class MyPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var pages = [UIViewController]()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.delegate = self
        self.dataSource = self

        let page1: UIViewController! = storyboard?.instantiateViewControllerWithIdentifier("page1")
        let page2: UIViewController! = storyboard?.instantiateViewControllerWithIdentifier("page2")

        pages.append(page1)
        pages.append(page2)

        setViewControllers([page1], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        let currentIndex = pages.indexOf(viewController)!
        let previousIndex = abs((currentIndex - 1) % pages.count)
        return pages[previousIndex]
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        let currentIndex = pages.indexOf(viewController)!
        let nextIndex = abs((currentIndex + 1) % pages.count)
        return pages[nextIndex]
    }

    func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
        return pages.count
    }

    func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
        return 0
    }
}

コンテナビューでUIPageViewControllerを使用 ストーリーボードのセットアップで詳細をご覧ください。

11
samwize

StoryboardのUIPageViewControllerに関する質問はたくさんあるようです。

デモコード は、画面の小さな領域のみをページングする場合に、ストーリーボードでUIPageViewControllerをスタンドアロンの全画面表示またはUIContainerViewとして使用する方法を示します。

enter image description hereenter image description hereenter image description here

5
William T.

Swift 3:

class YourPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var pages = [UIViewController]()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.delegate = self
        self.dataSource = self

        let page1: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "page1")
        let page2: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "page2")

        pages.append(page1)
        pages.append(page2)

        setViewControllers([page1], direction: UIPageViewControllerNavigationDirection.forward, animated: false, completion: nil)
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        let currentIndex = pages.index(of: viewController)!
        let previousIndex = abs((currentIndex - 1) % pages.count)
        return pages[previousIndex]
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        let currentIndex = pages.index(of: viewController)!
        let nextIndex = abs((currentIndex + 1) % pages.count)
        return pages[nextIndex]
    }

    func presentationIndex(for pageViewController: UIPageViewController) -> Int {
        return pages.count
    }
}
1
PLJNS

Swift 5の回答:

import UIKit

class MyPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var allViewControllers = [UIViewController]()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.dataSource = self

        let vc1: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "viewController1")
        let vc2: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "viewController2")
        allViewControllers = [vc1, vc2]

        self.setViewControllers([vc1], direction: UIPageViewController.NavigationDirection.forward, animated: false)
    }

    // UIPageViewControllerDataSource

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController?
    {
        let currentIndex = allViewControllers.firstIndex(of: viewController)!
        return currentIndex == 0 ? nil : allViewControllers[currentIndex-1]
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?
    {
        let currentIndex = allViewControllers.firstIndex(of: viewController)!
        return currentIndex == allViewControllers.count-1 ? nil : allViewControllers[currentIndex+1]
    }

    func presentationCount(for pageViewController: UIPageViewController) -> Int
    {
      return allViewControllers.count
    }

    func presentationIndex(for pageViewController: UIPageViewController) -> Int
    {
        return 0
    }
}
0
jrc

@samwizeの答えを使用して無限にスクロールバックするには、負の値をチェックする条件を追加する必要があります。それ以外の場合は、最初のページと2番目のページを切り替えるだけです。これは、3ページ以上を予定している場合にのみ必要です。

func pageViewController(_ pageViewController: UIPageViewController,
                            viewControllerBefore viewController: UIViewController) -> UIViewController? {
        let currentIndex = pages.index(of: viewController)!
        var previousIndex = (currentIndex - 1) % pages.count
        if previousIndex < 0 {previousIndex = pages.count - 1}
        return pages[previousIndex]
    }
0
Aquila Sagitta