zl程序教程

您现在的位置是:首页 >  其它

当前栏目

UIPageViewController实现界面左右滑动

实现 界面 滑动 左右
2023-09-11 14:14:25 时间

UIPageViewController是iOS 5.0之后提供的一个分页控件可以实现图片轮播效果和翻书效果,使用起来也很简单方便。

初始化

- (instancetype)initWithTransitionStyle:(UIPageViewControllerTransitionStyle)style 
    navigationOrientation:(UIPageViewControllerNavigationOrientation)navigationOrientation 
    options:(nullable NSDictionary<UIPageViewControllerOptionsKey, id> *)options;
  • style:

这个参数是UIPageViewController翻页的过渡样式,系统提供了两种过度样式,分别是

typedef NS_ENUM(NSInteger, UIPageViewControllerTransitionStyle) {
    UIPageViewControllerTransitionStylePageCurl = 0,  //卷曲样式类似翻书效果
    UIPageViewControllerTransitionStyleScroll = 1     //UIScrollView滚动效果
};
  • navigationOrientation

这个参数是UIPageViewController导航方向,系统提供了两种方式,分别是

typedef NS_ENUM(NSInteger, UIPageViewControllerNavigationOrientation) {
    UIPageViewControllerNavigationOrientationHorizontal = 0,    //水平导航方式
    UIPageViewControllerNavigationOrientationVertical = 1       //垂直导航方式
};

对应只读属性:

  • options

这个参数是可选的,传入的是对UIPageViewController的一些配置组成的字典,不过这个参数只能以UIPageViewControllerOptionSpineLocationKey和UIPageViewControllerOptionInterPageSpacingKey这两个key组成的字典。

  1. UIPageViewControllerOptionSpineLocationKey 这个key只有在style是翻书效果UIPageViewControllerTransitionStylePageCurl的时候才有作用,它定义的是书脊的位置,值对应着UIPageViewControllerSpineLocation这个枚举项。
  2. UIPageViewControllerOptionInterPageSpacingKey 这个key只有在style是滚动效果UIPageViewControllerTransitionStyleScroll的时候才有作用,它定义的是两个页面之间的间距(默认间距是0)。

属性

  • 翻页过渡样式:

只读属性,对应initWithTransitionStyle方法的style参数

@property (nonatomic, readonly) UIPageViewControllerTransitionStyle transitionStyle;
  • 导航方向:

只读属性,对应initWithTransitionStyle方法的navigationOrientation参数

@property (nonatomic, readonly) UIPageViewControllerNavigationOrientation navigationOrientation;
  • 书脊位置:
@property (nonatomic, readonly) UIPageViewControllerSpineLocation spineLocation;
typedef NS_ENUM(NSInteger, UIPageViewControllerSpineLocation) {
    UIPageViewControllerSpineLocationNone = 0, // Returned if 'spineLocation' is queried when 'transitionStyle' is not 'UIPageViewControllerTransitionStylePageCurl'.
    UIPageViewControllerSpineLocationMin = 1,  // Requires one view controller.
    UIPageViewControllerSpineLocationMid = 2,  // Requires two view controllers.
    UIPageViewControllerSpineLocationMax = 3   // Requires one view controller.
};   // Only pertains to 'UIPageViewControllerTransitionStylePageCurl'.
  • 双页样式:
@property (nonatomic, getter=isDoubleSided) BOOL doubleSided;

这个属性默认为NO,如果我们当前屏幕仅展示一个页面那么不用设置这个属性,如果spineLocation设置了UIPageViewControllerSpineLocationMid这个选项,效果是翻开的书,这样屏幕展示的就是两个页面,这个属性就必须设置为YES了。

  • 设置UIPageViewController要显示的页面:
- (void)setViewControllers:(nullable NSArray<UIViewController *> *)viewControllers 
    direction:(UIPageViewControllerNavigationDirection)direction 
    animated:(BOOL)animated 
    completion:(void (^ __nullable)(BOOL finished))completion;

如果doubleSided设为YES了,那么viewControllers这个参数至少包含两个页面。 

UIPageViewControllerNavigationDirection为翻页方向: 

typedef NS_ENUM(NSInteger, UIPageViewControllerNavigationDirection) {
    UIPageViewControllerNavigationDirectionForward,    //前进
    UIPageViewControllerNavigationDirectionReverse     //后退
};

数据源和代理

  • 代理 <UIPageViewControllerDelegate>
// UIPageViewController开始滚动或翻页的时候触发
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers API_AVAILABLE(ios(6.0));

// UIPageViewController结束滚动或翻页的时候触发
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray<UIViewController *> *)previousViewControllers transitionCompleted:(BOOL)completed;

// 在style是UIPageViewControllerTransitionStylePageCurl 并且横竖屏状态变化的时候触发, 我们可以重新设置书脊的位置
// 比如屏幕是竖屏状态的时候我们就设置书脊位置是UIPageViewControllerSpineLocationMin或UIPageViewControllerSpineLocationMax
// 如果屏幕是横屏状态的时候我们可以设置书脊位置是UIPageViewControllerSpineLocationMid
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation API_UNAVAILABLE(tvos);

// 设置UIPageViewController支持的屏幕类型
- (UIInterfaceOrientationMask)pageViewControllerSupportedInterfaceOrientations:(UIPageViewController *)pageViewController API_AVAILABLE(ios(7.0)) API_UNAVAILABLE(tvos);
- (UIInterfaceOrientation)pageViewControllerPreferredInterfaceOrientationForPresentation:(UIPageViewController *)pageViewController API_AVAILABLE(ios(7.0)) API_UNAVAILABLE(tvos);
  • 数据源 <UIPageViewControllerDataSource>
// 返回前一个页面,如果返回为nil,那么UIPageViewController就会认为当前页面是第一个页面不可以向前滚动或翻页
- (nullable UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController;
// 返回下一个页面,如果返回为nil,那么UIPageViewController就会认为当前页面是最后一个页面不可以向后滚动或翻页
- (nullable UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController;


@optional

// A page indicator will be visible if both methods are implemented, transition style is 'UIPageViewControllerTransitionStyleScroll', and navigation orientation is 'UIPageViewControllerNavigationOrientationHorizontal'.
// Both methods are called in response to a 'setViewControllers:...' call, but the presentation index is updated automatically in the case of gesture-driven navigation.
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController API_AVAILABLE(ios(6.0)); // The number of items reflected in the page indicator.
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController API_AVAILABLE(ios(6.0)); // The selected item reflected in the page indicator.

实现示例

@interface ViewController ()<UIPageViewControllerDelegate, UIPageViewControllerDataSource>

@property (nonatomic, strong) UIPageViewController *pageViewController;
@property (nonatomic, strong) NSArray *controllers;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSDictionary *options = @{UIPageViewControllerOptionSpineLocationKey:@(UIPageViewControllerSpineLocationMin)};
    _pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:options];
    _pageViewController.delegate = self;
    _pageViewController.dataSource = self;
    _pageViewController.view.frame = self.view.bounds;
    [self addChildViewController:self.pageViewController];
    [self.view addSubview:self.pageViewController.view];
    
    UIViewController *leftCtrl = [[UIViewController alloc] init];
    leftCtrl.view.backgroundColor = [UIColor redColor];
    UIViewController *midCtrl = [[UIViewController alloc] init];
    midCtrl.view.backgroundColor = [UIColor greenColor];
    UIViewController *rightCtrl = [[UIViewController alloc] init];
    rightCtrl.view.backgroundColor = [UIColor blueColor];
    self.controllers = @[leftCtrl, midCtrl, rightCtrl];
    // 设置UIPageViewController的配置项
    [_pageViewController setViewControllers:@[_controllers[0]]
                                  direction:UIPageViewControllerNavigationDirectionForward
                                   animated:NO
                                 completion:nil];
}

#pragma mark - UIPageViewControllerDataSource
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
    NSUInteger index = [self.controllers indexOfObject:viewController];
    index = (index+self.controllers.count-1)%self.controllers.count;
    return self.controllers[index];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
    NSUInteger index = [self.controllers indexOfObject:viewController];
    index = (index+1)%self.controllers.count;
    return self.controllers[index];
}

#pragma mark - UIPageViewControllerDelegate
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers {
    NSLog(@"%s", __func__);
}

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
    NSLog(@"%s", __func__);
}

@end