UIPageViewController简介
UIPageViewController是iOS 5.0之后提供的一个分页控件可以实现图片轮播效果和翻书效果.使用起来也很简单方便.
UIPageViewController使用
初始化
进入系统API你可以找到iOS SDK提供的初始化方法
- (instancetype)initWithTransitionStyle:(UIPageViewControllerTransitionStyle)style
navigationOrientation:(UIPageViewControllerNavigationOrientation)navigationOrientation
options:(nullable NSDictionary<NSString *, id> *)options NS_DESIGNATED_INITIALIZER;
初始化方法提供三个参数:
- style: 这个参数是UIPageViewController翻页的过渡样式,系统提供了两种过度样式,分别是
- UIPageViewControllerTransitionStylePageCurl : 卷曲样式类似翻书效果
- UIPageViewControllerTransitionStyleScroll : UIScrollView滚动效果
- navigationOrientation: 这个参数是UIPageViewController导航方向,系统提供了两种方式,分别是
- UIPageViewControllerNavigationOrientationHorizontal : 水平导航方式
- UIPageViewControllerNavigationOrientationVertical : 垂直导航方式
- options: 这个参数是可选的,传入的是对UIPageViewController的一些配置组成的字典,不过这个参数只能以UIPageViewControllerOptionSpineLocationKey和UIPageViewControllerOptionInterPageSpacingKey这两个key组成的字典.
- UIPageViewControllerOptionSpineLocationKey 这个key只有在style是翻书效果UIPageViewControllerTransitionStylePageCurl的时候才有作用, 它定义的是书脊的位置,值对应着UIPageViewControllerSpineLocation这个枚举项,不要定义错了哦.
- UIPageViewControllerOptionInterPageSpacingKey这个key只有在style是UIScrollView滚动效果UIPageViewControllerTransitionStyleScroll的时候才有作用, 它定义的是两个页面之间的间距(默认间距是0).
除了初始化方法系统还提供了一个属性
@property (nonatomic, getter=isDoubleSided) BOOL doubleSided; // Default is 'NO'.
这个属性默认为NO,如果我们当前屏幕仅展示一个页面那么不用设置这个属性,如果设置了UIPageViewControllerSpineLocationMid这个选项,效果是翻开的书这样屏幕展示的就是两个页面,这个属性就必须设置为YES了.
此外还有一个重要方法:
- (void)setViewControllers:(nullable NSArray<UIViewController *> *)viewControllers
direction:(UIPageViewControllerNavigationDirection)direction
animated:(BOOL)animated
completion:(void (^ __nullable)(BOOL finished))completion;
这个方法是设置UIPageViewController初始显示的页面,如果doubleSided设为YES了,那么viewControllers这个参数至少包含两个页面.
数据源和代理
UIPageViewController类似UITableViewController机制可以设置数据源和代理.
数据源 <UIPageViewControllerDataSource>
iOS SDK提供了四个数据源方法,其中两个为@required,另外两个是@optional.
@required
- (nullable UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController;
这个方法是返回前一个页面,如果返回为nil,那么UIPageViewController就会认为当前页面是第一个页面不可以向前滚动或翻页
- (nullable UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController;
这个方法是下一个页面,如果返回为nil,那么UIPageViewController就会认为当前页面是最后一个页面不可以向后滚动或翻页
代理 <UIPageViewControllerDelegate>
iOS SDK提供了五个代理方法:
// Sent when a gesture-initiated transition begins.
- (void)pageViewController:(UIPageViewController *)pageViewController
willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers NS_AVAILABLE_IOS(6_0);
这个方法是UIPageViewController开始滚动或翻页的时候触发
// Sent when a gesture-initiated transition ends. The 'finished' parameter indicates whether the animation finished, while the 'completed' parameter indicates whether the transition completed or bailed out (if the user let go early).
- (void)pageViewController:(UIPageViewController *)pageViewController
didFinishAnimating:(BOOL)finished
previousViewControllers:(NSArray<UIViewController *> *)previousViewControllers
transitionCompleted:(BOOL)completed;
这个方法是在UIPageViewController结束滚动或翻页的时候触发
// Delegate may specify a different spine location for after the interface orientation change. Only sent for transition style 'UIPageViewControllerTransitionStylePageCurl'.
// Delegate may set new view controllers or update double-sided state within this method's implementation as well.
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation __TVOS_PROHIBITED;
这个方法是在style是UIPageViewControllerTransitionStylePageCurl 并且横竖屏状态变化的时候触发,我们可以重新设置书脊的位置,比如如果屏幕是竖屏状态的时候我们就设置书脊位置是UIPageViewControllerSpineLocationMin或UIPageViewControllerSpineLocationMax, 如果屏幕是横屏状态的时候我们可以设置书脊位置是UIPageViewControllerSpineLocationMid
- (UIInterfaceOrientationMask)pageViewControllerSupportedInterfaceOrientations:(UIPageViewController *)pageViewController NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;
- (UIInterfaceOrientation)pageViewControllerPreferredInterfaceOrientationForPresentation:(UIPageViewController *)pageViewController NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;
这两个方法设置了UIPageViewController支持的屏幕类型
实现效果
翻书效果
直接上代码和效果
ViewController的.m代码如下:
@interface ViewController () <UIPageViewControllerDelegate, UIPageViewControllerDataSource>
@property (nonatomic, strong) UIPageViewController *pageViewController;
@property (nonatomic, strong) NSArray *pageContentArray;
@end
@implementation ViewController
#pragma mark - Lazy Load
- (NSArray *)pageContentArray {
if (!_pageContentArray) {
NSMutableArray *arrayM = [[NSMutableArray alloc] init];
for (int i = 1; i < 10; i++) {
NSString *contentString = [[NSString alloc] initWithFormat:@"This is the page %d of content displayed using UIPageViewController", i];
[arrayM addObject:contentString];
}
_pageContentArray = [[NSArray alloc] initWithArray:arrayM];
}
return _pageContentArray;
}
#pragma mark - Life Cycle
- (void)viewDidLoad {
[super viewDidLoad];
// 设置UIPageViewController的配置项
// NSDictionary *options = @{UIPageViewControllerOptionInterPageSpacingKey : @(20)};
NSDictionary *options = @{UIPageViewControllerOptionSpineLocationKey : @(UIPageViewControllerSpineLocationMin)};
// 根据给定的属性实例化UIPageViewController
_pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:options];
// 设置UIPageViewController代理和数据源
_pageViewController.delegate = self;
_pageViewController.dataSource = self;
// 设置UIPageViewController初始化数据, 将数据放在NSArray里面
// 如果 options 设置了 UIPageViewControllerSpineLocationMid,注意viewControllers至少包含两个数据,且 doubleSided = YES
ContentViewController *initialViewController = [self viewControllerAtIndex:0];// 得到第一页
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[_pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionReverse
animated:NO
completion:nil];
// 设置UIPageViewController 尺寸
_pageViewController.view.frame = self.view.bounds;
// 在页面上,显示UIPageViewController对象的View
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
}
#pragma mark - UIPageViewControllerDataSource And UIPageViewControllerDelegate
#pragma mark 返回上一个ViewController对象
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [self indexOfViewController:(ContentViewController *)viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
// 返回的ViewController,将被添加到相应的UIPageViewController对象上。
// UIPageViewController对象会根据UIPageViewControllerDataSource协议方法,自动来维护次序
// 不用我们去操心每个ViewController的顺序问题
return [self viewControllerAtIndex:index];
}
#pragma mark 返回下一个ViewController对象
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [self indexOfViewController:(ContentViewController *)viewController];
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.pageContentArray count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
#pragma mark - 根据index得到对应的UIViewController
- (ContentViewController *)viewControllerAtIndex:(NSUInteger)index {
if (([self.pageContentArray count] == 0) || (index >= [self.pageContentArray count])) {
return nil;
}
// 创建一个新的控制器类,并且分配给相应的数据
ContentViewController *contentVC = [[ContentViewController alloc] init];
contentVC.content = [self.pageContentArray objectAtIndex:index];
return contentVC;
}
#pragma mark - 数组元素值,得到下标值
- (NSUInteger)indexOfViewController:(ContentViewController *)viewController {
return [self.pageContentArray indexOfObject:viewController.content];
}
@end
ContentViewController的.h代码
@interface ContentViewController : UIViewController
@property (nonatomic, copy) NSString *content;
@end
ContentViewController的.m代码
#define kRandomColor ([UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0f])
@interface ContentViewController ()
@property (nonatomic, strong) UILabel *contentLabel;
@end
@implementation ContentViewController
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = kRandomColor;
_contentLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, 100)];
_contentLabel.numberOfLines = 0;
_contentLabel.backgroundColor = kRandomColor;
[self.view addSubview:_contentLabel];
}
- (void) viewWillAppear:(BOOL)paramAnimated{
[super viewWillAppear:paramAnimated];
_contentLabel.text = _content;
}
@end
滚动效果
关于滚动效果只需将初始化配置修改一下即可:
// 设置UIPageViewController的配置项
NSDictionary *options = @{UIPageViewControllerOptionInterPageSpacingKey : @(20)};
// NSDictionary *options = @{UIPageViewControllerOptionSpineLocationKey : @(UIPageViewControllerSpineLocationMin)};
// 根据给定的属性实例化UIPageViewController
_pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:options];
UIPageViewController 总结
关于UIPageViewController的使用就介绍这么多,关键点在于UIPageViewController的配置项的设置以及数据源的控制.
希望这篇文章会对你有所帮助
Demo地址 https://github.com/Herb-Sun/UIPageViewControllerDemo