Подтвердить что ты не робот

UIPageViewController и раскадровка

Я пытаюсь настроить UIPageViewController SPECIFICALLY из раскадровки:

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). Нет пользователей взаимодействие уже доступно.
4b9b3361

Ответ 1

Ответ 2017 года.

В настоящее время сделать это очень просто, просто используя раскадровку.

Подобные "ползучие полноэкранные уроки" были популярны некоторое время как "заставки" приложений, поэтому я назвал класс ниже IntroPages.

Шаг 1, создайте контейнерное представление, которое является UIPageViewController.

Если вы новичок в iOS, вот руководство по просмотру контейнера.

(Примечание. Если вы не знаете, как изменить представление контейнера на UIPageViewController, прокрутите вниз до раздела "Как изменить..." этого руководства.

enter image description here)

Вы можете сделать контейнер любой желаемой формы. Как и в любом представлении контейнера, оно может быть полноэкранным или небольшой частью экрана - все, что вы хотите.

Шаг 2,

Создайте четыре простых контроллера вида, которые могут быть чем угодно - изображения, текст, таблицы, что угодно. (Фиолетовый в примере.)

four controllers

Обратите внимание, что они просто находятся на вашей раскадровке, не связывая их ни с чем.

Шаг 3, вы должны установить идентификаторы этих четырех страниц. "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

очень вероятно, что вы хотите "Свиток", а не другой.

Ответ 2

Для кого-то, кто хочет видеть прокрутку рабочей страницы (вперед/назад)

-(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];
    } 

Ответ 3

Расширение Joe Blow answer с кодом 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 с представлением контейнера с настройкой раскадровки.

Ответ 4

Кажется, у нас много вопросов относительно UIPageViewController в Storyboard.

Вот некоторый демонстрационный код, чтобы показать вам, как вы можете использовать UIPageViewController в раскадровке как автономный полноэкранный режим или как UIContainerView, если вы хотите разместить только небольшую область экрана.

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

Ответ 5

Обновлен для 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
    }
}

Ответ 6

Чтобы иметь бесконечный прокрутка назад с помощью ответа @samwize, вам нужно добавить условие для проверки отрицательных значений. В противном случае вы просто переключаетесь между первой и второй страницей. Это необходимо, только если вы планируете иметь более двух страниц.

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

Ответ 7

Ответ на 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
    }
}

Ответ 8

Проблема заключается в том, что вы неправильно используете экземпляры UIViewController:

myViewControllers = @[tuto1, tuto2, tuto1, tuto2];

Я предлагаю вам иметь NSMutableSet, который будет служить пулом повторных экземпляров UIViewController.

В viewControllerBeforeViewController: и viewControllerBeforeViewController: найдите NSMutableSet с помощью NSPredicate, чтобы найти UIViewController с parentViewController равным nil. Если вы его найдете, верните. Если нет, создайте новый экземпляр, добавьте его в NSMutableSet и верните его.

Когда вы закончите и ваши тесты пройдут, вы можете извлечь пул в свой класс.