ios UIPageViewController 和故事板
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18398796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIPageViewController and storyboard
提问by Benjamin Toueg
I'm trying to configure a UIPageViewController SPECIFICALLY from storyboard:
我正在尝试从情节提要中特别配置 UIPageViewController:
TutorialPageViewController.h
TutorialPageViewController.h
#import <UIKit/UIKit.h>
@interface TutorialPageViewController : UIPageViewController <UIPageViewControllerDelegate, UIPageViewControllerDataSource>
@end
TutorialPageViewController.m
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
Problem is...
问题是...
- The first page displays well with the page indicator. While swiping,
- I can see properly the second page.
- As soon as the transition finishes, I get a black screen (with the page indicator properly displaying page number 2). No user interaction is available anymore.
- 第一页与页面指示器显示良好。滑动的同时,
- 我可以正确地看到第二页。
- 转换完成后,我会看到一个黑屏(页面指示器正确显示第 2 页)。用户交互不再可用。
回答by Fattie
2020. Swift updated.
2020. Swift 更新。
2017 answer...
2017答案...
Nowadays it is dead easy to do this simply using Storyboard.
如今,只需使用 Storyboard就可以轻松做到这一点。
These sort of "swiping full-screen tutorials" were popular as app "intros" for awhile, so I called the class below IntroPages
.
这种“滑动全屏教程”作为应用程序的“介绍”流行了一段时间,所以我称之为下面的课程IntroPages
。
Step 1, make a container view that is a UIPageViewController.
第 1 步,创建一个 UIPageViewController 容器视图。
If new to iOS, here is a container view tutorial.
如果是 iOS 新手,这里有一个容器视图教程。
( Note: if you don't know how to change the container view to a UIPageViewController, scroll down to the section "How to change..."on that tutorial.
(注意:如果您不知道如何将容器视图更改为 UIPageViewController,请向下滚动到该教程中的“如何更改...”部分。
You can make the container any shape you want. As with any container view, it can be full-screen or a small part of the screen - whatever you want.
你可以把容器做成任何你想要的形状。与任何容器视图一样,它可以是全屏或屏幕的一小部分 - 无论您想要什么。
Step 2,
第2步,
Make four straightforward view controllers which can be anything you want- images, text, tables, anything at all. (Purple in the example.)
制作四个简单的视图控制器,它们可以是你想要的任何东西——图像、文本、表格,任何东西。(示例中为紫色。)
Note that they simply sit there on your storyboard, do not link them to anything.
请注意,它们只是坐在你的故事板上,不要将它们链接到任何东西。
Step 3, you must Set the IDsof those four pages. "id1", "id2", "id4", "id4" is fine.
第 3 步,您必须设置这四个页面的 ID。“id1”、“id2”、“id4”、“id4”都可以。
Step 4, copy and paste! Here's the class IntroPages,
第四步,复制粘贴!这是 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: UIPageViewController.NavigationDirection.forward, animated: false, completion: nil)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController)-> UIViewController? {
let cur = pages.firstIndex(of: viewController)!
// if you prefer to NOT scroll circularly, simply add here:
// if cur == 0 { return nil }
var prev = (cur - 1) % pages.count
if prev < 0 {
prev = pages.count - 1
}
return pages[prev]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController)-> UIViewController? {
let cur = pages.firstIndex(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
}
}
(Look at the comments - there is code for either looping or linear paging as you prefer.)
(查看注释 - 根据您的喜好,有用于循环或线性分页的代码。)
That's all there is to it - you're done.
这就是它的全部 - 你已经完成了。
You simply set the transition style on the storyboard,
您只需在情节提要上设置过渡样式,
it is very likely that you want "Scroll", not the other one.
您很可能想要“滚动”,而不是另一个。
回答by EditOR
For someone, who wants to see working page scroll (forward / backward)
对于想要查看工作页面滚动(向前/向后)的人
-(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
}
}
Just to add to this great answer by EditOR, here's what you do if you prefer "round and around" paging: still using the same technique of 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];
}
回答by samwize
Extending Joe Blow's answerwith Swift code for the UIPageViewController
class:
使用类的Swift 代码扩展Joe Blow 的回答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
}
}
Read more on using UIPageViewController with container viewwith storyboard setup.
阅读更多关于使用 UIPageViewController 和带有故事板设置的容器视图。
回答by William T.
There seems to be a lot of questions regarding UIPageViewController in Storyboard.
似乎有很多关于 Storyboard 中 UIPageViewController 的问题。
Here is some demo codeto show you how you can use the UIPageViewController in storyboard as a standalone full screen view or as a UIContainerView, if you want to page only a small area of your screen.
下面是一些演示代码,向您展示如何将故事板中的 UIPageViewController 作为独立的全屏视图或作为 UIContainerView 使用,如果您只想对屏幕的一小部分区域进行分页。
回答by PLJNS
Updated for Swift 3:
为 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
}
}
回答by Aquila Sagitta
To have infinite scroll back using @samwize's answer you need to add conditional to check for negative values. Otherwise you just switch between the first and second page. This is only necessary if you plan on having more than two pages.
要使用@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]
}
回答by jrc
Answer for Swift 5:
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
}
}
回答by Rudolf Adamkovi?
The problem is that you're improperly reusing UIViewController
instances:
问题是您不正确地重用UIViewController
实例:
myViewControllers = @[tuto1, tuto2, tuto1, tuto2];
I would suggest you to have an NSMutableSet
that would serve as a pool of reusable UIViewController
instances.
我建议您拥有一个NSMutableSet
可用作可重用UIViewController
实例池的对象。
In viewControllerBeforeViewController:
and viewControllerBeforeViewController:
search your NSMutableSet
using NSPredicate
to find a UIViewController
with parentViewController
equal to nil
. If you find one, return it. If not, instantiate a new one, add it to the NSMutableSet
and then return it.
在viewControllerBeforeViewController:
和viewControllerBeforeViewController:
搜索您NSMutableSet
使用NSPredicate
找到一个UIViewController
具有parentViewController
相等nil
。如果你找到了,就退货。如果没有,则实例化一个新的,将其添加到 中NSMutableSet
,然后返回它。
When you're done and your tests are passing, you can extract the pool into its own class.
完成并且测试通过后,您可以将池提取到它自己的类中。