先说初始化

- (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. js系列教程11-json、ajax(XMLHttpRequest)、comet、SSE、WebSocket全解

    js系列教程11-json.ajax(XMLHttpRequest).comet.SSE.WebSocket全解:https://blog.csdn.net/luanpeng825485697/art ...

  2. 线程分离pthread_detach()中的return()和pthread_exit()

    #include <stdio.h> #include <pthread.h> pthread_t tid[]; void *func_2(void *arg); void * ...

  3. BUUCTF MISC ZIP

    这道题有点烦,拿出来单独写先贴两张图,一会用 首先这题给了68个压缩包,每个压缩包里只有4bytes大小,于是可以想到是crc爆破,自己写的脚本总是被killed,犯懒找了个脚本 import zip ...

  4. C#5.0 异步编程 Async和Await--理解异步方法与线程之间的关系

    这次来理解一下异步方法与线程之间的关系 新建一个控制台程序 代码如下 static void Main(string[] args) { Console.WriteLine("\n进入Mai ...

  5. 微信小程序の模板

    一.什么是模板 模板顾名思义就是可以复用的代码块.减少编码工作量. 二.例子 <template name="templateTest"> <view>th ...

  6. 【JS学习】慕课网8-17编程练习 网页的返回与跳转

    编程练习 制作一个跳转提示页面: 要求: 1. 如果打开该页面后,如果不做任何操作则5秒后自动跳转到一个新的地址,如慕课网主页. 2. 如果点击“返回”按钮则返回前一个页面. 代码如下: 需要注意的是 ...

  7. Android 使用android-support-multidex解决Dex超出方法数的限制问题,让你的应用不再爆棚(转)

    如有转载,请声明出处: 时之沙: http://blog.csdn.net/t12x3456    (来自时之沙的csdn博客) 随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sd ...

  8. Internet History 课程笔记

    课程地址:https://www.coursera.org/learn/internet-history 科学|上网可解决视频加载不出来的问题 Week 1 High Stakes Research ...

  9. Java Number&Math类

    Java Number类 一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte.int.long.double等. 实例 int i = 5000; float gpa = 13.65 ...

  10. go解析markdown转成html

    一.代码 package main import ( "fmt" "github.com/microcosm-cc/bluemonday" "gith ...