iOS UIPageViewController使用
UIPageViewController是iOS 5.0之后提供的一个分页控件可以实现图片轮播效果和翻书效果.使用起来简单方便.
一、初始化方法
- (instancetype)initWithTransitionStyle:(UIPageViewControllerTransitionStyle)style
navigationOrientation:(UIPageViewControllerNavigationOrientation)navigationOrientation
options:(nullable NSDictionary<NSString *, id> *)options NS_DESIGNATED_INITIALIZER;
初始化方法三个参数:
※翻转样式枚举
typedef NS_ENUM(NSInteger, UIPageViewControllerTransitionStyle) {
UIPageViewControllerTransitionStylePageCurl = 0, //翻书效果样式
UIPageViewControllerTransitionStyleScroll = 1 //滑屏效果样式
};
※滚动方向
typedef NS_ENUM(NSInteger, UIPageViewControllerNavigationOrientation) {
UIPageViewControllerNavigationOrientationHorizontal = 0, //水平
UIPageViewControllerNavigationOrientationVertical = 1 //垂直
};
※options:
可选。传入的是对UIPageViewController的配置组成的字典。key可以是:
1、UIPageViewControllerOptionSpineLocationKey(Style为UIPageViewControllerTransitionStylePageCurl时有效), 它定义的是书脊的位置
※书脊位置枚举,决定首页显示的视图个数
typedef NS_ENUM(NSInteger, UIPageViewControllerSpineLocation) {
UIPageViewControllerSpineLocationNone = 0, //没有书脊,滚动显示视图
UIPageViewControllerSpineLocationMin = 1, // 书脊居左或上,首页显示一个视图
UIPageViewControllerSpineLocationMid = 2, // 书脊居中,首页显示两个视图
UIPageViewControllerSpineLocationMax = 3 // 书脊居右或下,显示一个视图
};
2、UIPageViewControllerOptionInterPageSpacingKey(Style为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这个参数至少包含两个页面.
※翻页方式枚举
typedef NS_ENUM(NSInteger, UIPageViewControllerNavigationDirection) {
UIPageViewControllerNavigationDirectionForward, //从左往右(或从下往上)翻页
UIPageViewControllerNavigationDirectionReverse //从右往左(或从上往下)翻页
};
二、数据源和代理:
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
翻书效果.gif
滚动效果
关于滚动效果只需将初始化配置修改一下即可:
// 设置UIPageViewController的配置项
NSDictionary *options = @{UIPageViewControllerOptionInterPageSpacingKey : @(20)};
// NSDictionary *options = @{UIPageViewControllerOptionSpineLocationKey : @(UIPageViewControllerSpineLocationMin)};
// 根据给定的属性实例化UIPageViewController
_pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:options];
滚动效果.gif
作者:herbsun
链接:https://www.jianshu.com/p/46c8c585d50b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
上一篇: 深入理解UIScrollView