先说初始化

- (UIPageViewController *)PageViewController{
if(!_PageViewController){
//书脊位置,只有在UIPageViewControllerTransitionStylePageCurl才生效
NSDictionary *options =[NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:UIPageViewControllerSpineLocationMin]
forKey: UIPageViewControllerOptionSpineLocationKey];
//两个page之间的间距,只有UIPageViewControllerTransitionStyleScroll格式才生效
// NSDictionary *options =[NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:0]
// forKey: UIPageViewControllerOptionInterPageSpacingKey];
_PageViewController = [[ UIPageViewController alloc]initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:options];
_PageViewController.view.backgroundColor = [UIColor clearColor];
_PageViewController.dataSource = self;
_PageViewController.delegate = self;
}
return _PageViewController;
}

然后填充内容

//填充PageView
- (void)setPageViewData{
[self.controllerArray removeAllObjects];
ReadingSubViewController *subView = [self viewControllerAtIndex:0];
[self.controllerArray addObject:subView];
[self.PageViewController setViewControllers:self.controllerArray direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL finished) {
}];
} - (ReadingSubViewController *)viewControllerAtIndex:(NSInteger)index{
NSLog(@"push%ld",index);
ReadingSubViewController *subView = [[ReadingSubViewController alloc]init];
subView.pageModel = self.bookpageData[index];
subView.bookModel = self.model;
subView.pageIndex = index;
_open = YES;
[self pushButtonClick];
return subView;
}

&&重点

重点是是他内部的运行逻辑,我也是今天才完全搞清楚。

先看delegate

#pragma mark ==========PageVCDelegate==========
//这个方法是返回前一个页面,如果返回为nil,那么UIPageViewController就会认为当前页面是第一个页面不可以向前滚动或翻页
- (nullable UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController{
NSInteger index = [self getIndex:(ReadingSubViewController *)viewController];
NSLog(@"before=%ld",index);
if (index == 0 || index == NSNotFound) {
return nil;
}
index -- ;
ReadingSubViewController *playVC = [self viewControllerAtIndex:index];
if (index+1< 10) {
self.pageNumberLB.text = [NSString stringWithFormat:@"0%ld/%ld",index+1,_maxPage];
}else{
self.pageNumberLB.text = [NSString stringWithFormat:@"%ld/%ld",index+1,_maxPage];
}
return playVC;
}
//这个方法是下一个页面,如果返回为nil,那么UIPageViewController就会认为当前页面是最后一个页面不可以向后滚动或翻页
- (nullable UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController{
NSInteger index = [self getIndex:(ReadingSubViewController *)viewController];
if (index == NSNotFound || index == _maxPage - 1) {
return nil;
}
NSLog(@"after=%ld",index);
index ++;
ReadingSubViewController *playVC = [self viewControllerAtIndex:index];
if (index+1< 10) {
self.pageNumberLB.text = [NSString stringWithFormat:@"0%ld/%ld",index+1,_maxPage];
}else{
self.pageNumberLB.text = [NSString stringWithFormat:@"%ld/%ld",index+1,_maxPage];
}
return playVC;
}
- (NSInteger)getIndex:(ReadingSubViewController *)subVC{
return subVC.pageIndex;
}

如果TransitionStyle是UIPageViewControllerTransitionStylePageCurl

那么从首页开始拖动的时候,往左拖动,会触发viewControllerBeforeViewController这个代理方法,并不会触发viewControllerAfterViewController代理方法。

然后每次往右拖动时只会加载一个ViewController。上面整个流程的Log如下

eadingViewController.m[88] push0
ReadingViewController.m[102] before=0
ReadingViewController.m[121] after=0
ReadingViewController.m[88] push1
ReadingViewController.m[136] 开始滚动
ReadingViewController.m[140] isCompleted:成功
ReadingViewController.m[121] after=1
ReadingViewController.m[88] push2
ReadingViewController.m[136] 开始滚动
ReadingViewController.m[140] isCompleted:成功

如果TransitionStyle是UIPageViewControllerTransitionStyleScroll

那么从首页开始拖动,不管是往右还是往左,都肯定会viewControllerAfterViewController,为PageController加载好下个Page的ViewController。我往左拖动的Log如下

ReadingViewController.m[88] push0
ReadingViewController.m[102] before=0
ReadingViewController.m[121] after=0
ReadingViewController.m[88] push1

虽然拖动完成的代理方法没有执行。但是 viewControllerAfterViewController方法触发,加载好了下一页的ViewController内容。

然后往右拖动会提前加载第三页的内容Log如下

ReadingViewController.m[102] before=0
ReadingViewController.m[121] after=0
ReadingViewController.m[88] push1
ReadingViewController.m[136] 开始滚动
ReadingViewController.m[140] isCompleted:成功
ReadingViewController.m[121] after=1
ReadingViewController.m[88] push2

如果是开始就往右拖动的话Log如下

ReadingViewController.m[88] push0
ReadingViewController.m[121] after=0
ReadingViewController.m[88] push1
ReadingViewController.m[102] before=0
ReadingViewController.m[136] 开始滚动
ReadingViewController.m[140] isCompleted:成功
ReadingViewController.m[121] after=1
ReadingViewController.m[88] push2
ReadingViewController.m[136] 开始滚动
ReadingViewController.m[140] isCompleted:成功
ReadingViewController.m[121] after=2
ReadingViewController.m[88] push3

这是拖动到第三页的时候,但是第四页其实已经预加载好了。

之前一直没有用过UIPageViewControllerTransitionStyleScroll,今天用了一次才发现自己认识的很不清晰。做下记录

更新!

前面关于self.pageNumberLB.text,也就是当前页码的写法,如果是在UIPageViewControllerTransitionStylePageCurl格式下是没有问题的。但是如果是在UIPageViewControllerTransitionStyleScroll格式下。因为会有一个预加载,viewControllerAfterViewController会调用两次。所以会造成有误!

解决方法:还有两个协议方法

//这个方法是UIPageViewController开始滚动或翻页的时候触发
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers{
ReadingSubViewController *firstVC =(ReadingSubViewController *) pendingViewControllers.firstObject;
NSInteger index = firstVC.pageIndex;
NSLog(@"开始滚动%ld",index);
_animationIndex = index; }
//这个方法是在UIPageViewController结束滚动或翻页的时候触发
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray<UIViewController *> *)previousViewControllers transitionCompleted:(BOOL)completed{
NSLog(@"isCompleted:%@",completed?@"成功":@"失败");
if (completed) {
if (_animationIndex+< ) {
self.pageNumberLB.text = [NSString stringWithFormat:@"0%ld/%ld",_animationIndex+,_maxPage];
}else{
self.pageNumberLB.text = [NSString stringWithFormat:@"%ld/%ld",_animationIndex+,_maxPage];
}
} }

其实只用上面那个就可以基本满足,不过会有轻微的拖动一下虽然没有翻页成功也会改变页码字符的现象,配合下方的方法就完美了。

OVER

2019-10-31更新

最近一个项目也用到了PageViewController,开始是UIPageViewControllerTransitionStylePageCurl,后来想用UIPageViewControllerTransitionStyleScroll,发现坑太多了,改成了UICollectionView去代替。

如果style是UIPageViewControllerTransitionStyleScroll,不推荐用PageViewController,坑太多了!!

UIPageViewController看这篇就够了的更多相关文章

  1. ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了

    引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必是件很痛苦的事情吧,但文档又必须写,而且文档的格式如果没有具体要求的话,最终完成的文档则完全取决于开发者 ...

  2. .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了

    作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9985451.html 本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新 ...

  3. 想了解SAW,BAW,FBAR滤波器的原理?看这篇就够了!

    想了解SAW,BAW,FBAR滤波器的原理?看这篇就够了!   很多通信系统发展到某种程度都会有小型化的趋势.一方面小型化可以让系统更加轻便和有效,另一方面,日益发展的IC**技术可以用更低的成本生产 ...

  4. [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了

    [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 本文首发自:博客园 文章地址: https://www.cnblogs.com/yilezhu/p/ ...

  5. ExpandoObject与DynamicObject的使用 RabbitMQ与.net core(一)安装 RabbitMQ与.net core(二)Producer与Exchange ASP.NET Core 2.1 : 十五.图解路由(2.1 or earler) .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了

    ExpandoObject与DynamicObject的使用   using ImpromptuInterface; using System; using System.Dynamic; names ...

  6. Vue学习看这篇就够

    Vue -渐进式JavaScript框架 介绍 vue 中文网 vue github Vue.js 是一套构建用户界面(UI)的渐进式JavaScript框架 库和框架的区别 我们所说的前端框架与库的 ...

  7. 【转】ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了

    原文链接:https://www.cnblogs.com/yilezhu/p/9241261.html 引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必 ...

  8. Pycharm新手教程,只需要看这篇就够了

    pycharm是一款高效的python IDE工具,它非常强大,且可以跨平台,是新手首选工具!下面我给第一次使用这款软件的朋友做一个简单的使用教程,希望能给你带来帮助! 目前pycharm一共有两个版 ...

  9. Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) JAVA日志的前世今生 .NET MVC采用SignalR更新在线用户数 C#多线程编程系列(五)- 使用任务并行库 C#多线程编程系列(三)- 线程同步 C#多线程编程系列(二)- 线程基础 C#多线程编程系列(一)- 简介

    Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) 一.前言 由于本篇文章较长,所以下面给出内容目录方便跳转阅读,当然也可以用博客页面最右侧的文章目录导航栏进行跳转查阅. 一.前言 ...

随机推荐

  1. Emacs 25.1 error solved: url-http-create-request: Multibyte text in HTTP request

    Emacs 25.1 error solved: url-http-create-request: Multibyte text in HTTP request */--> code {colo ...

  2. echarts 给formatter文字添加不同颜色

    legend: { x : 'center', y : 'bottom', icon: "circle", itemWidth: 8, // 设置宽度 itemHeight: 8, ...

  3. stdio - 标准输入输出库函数

    SYNOPSIS 总览 #include <stdio.h> FILE *stdin; FILE *stdout; FILE *stderr; DESCRIPTION 描述 标注 I/O ...

  4. 爬虫(十二):图形验证码的识别、滑动验证码的识别(B站滑动验证码)

    1. 验证码识别 随着爬虫的发展,越来越多的网站开始采用各种各样的措施来反爬虫,其中一个措施便是使用验证码.随着技术的发展,验证码也越来越花里胡哨的了.最开始就是几个数字随机组成的图像验证码,后来加入 ...

  5. ZOJ-3524 拓扑排序+完全背包(好题)

    题意:在一个DAG上,主角初始有W钱起点在s点,每个点有一个代价wi和价值vi,主角从起点走到某一点不能回头走,一路上可以买东西(一个点的东西可以买无限次),且体力消耗为身上负重*路径长度.主角可以在 ...

  6. ie 图片拉伸

    终于发现只要设置img为 height:auto,width:auto,就不会出现这种情况了 img { height: auto; width: auto; }

  7. Java优化性能

    尽量在合适的场合使用单例使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面:第一,控制资源的使用,通过线程同步来控制资源的并 ...

  8. mongoose 常用数据库操作 更新

    更新 Model.update(conditions, update, [options], [callback]) db.js var mongoose = require('mongoose'); ...

  9. d3js 折线图+柱图

    <!DOCTYPE html> <html> <body> <div id="vis"><svg></svg> ...

  10. Dart编程实例 - 类型测试操作符 is!

    Dart编程实例 - 类型测试操作符 is! void main() { double n = 2.20; var num = n is! int; print(num); } 本文转自:http:/ ...