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). Нет пользователей
взаимодействие уже доступно.
Ответы
Ответ 1
Ответ 2017 года.
В настоящее время сделать это очень просто, просто используя раскадровку.
Подобные "ползучие полноэкранные уроки" были популярны некоторое время как "заставки" приложений, поэтому я назвал класс ниже IntroPages
.
Шаг 1, создайте контейнерное представление, которое является UIPageViewController.
Если вы новичок в iOS, вот руководство по просмотру контейнера.
(Примечание. Если вы не знаете, как изменить представление контейнера на UIPageViewController, прокрутите вниз до раздела "Как изменить..." этого руководства.
)
Вы можете сделать контейнер любой желаемой формы. Как и в любом представлении контейнера, оно может быть полноэкранным или небольшой частью экрана - все, что вы хотите.
Шаг 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
и верните его.
Когда вы закончите и ваши тесты пройдут, вы можете извлечь пул в свой класс.