UIPageViewController看这篇就够了
先说初始化
- (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看这篇就够了的更多相关文章
- ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了
引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必是件很痛苦的事情吧,但文档又必须写,而且文档的格式如果没有具体要求的话,最终完成的文档则完全取决于开发者 ...
- .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了
作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9985451.html 本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新 ...
- 想了解SAW,BAW,FBAR滤波器的原理?看这篇就够了!
想了解SAW,BAW,FBAR滤波器的原理?看这篇就够了! 很多通信系统发展到某种程度都会有小型化的趋势.一方面小型化可以让系统更加轻便和有效,另一方面,日益发展的IC**技术可以用更低的成本生产 ...
- [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了
[译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 本文首发自:博客园 文章地址: https://www.cnblogs.com/yilezhu/p/ ...
- 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 ...
- Vue学习看这篇就够
Vue -渐进式JavaScript框架 介绍 vue 中文网 vue github Vue.js 是一套构建用户界面(UI)的渐进式JavaScript框架 库和框架的区别 我们所说的前端框架与库的 ...
- 【转】ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了
原文链接:https://www.cnblogs.com/yilezhu/p/9241261.html 引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必 ...
- Pycharm新手教程,只需要看这篇就够了
pycharm是一款高效的python IDE工具,它非常强大,且可以跨平台,是新手首选工具!下面我给第一次使用这款软件的朋友做一个简单的使用教程,希望能给你带来帮助! 目前pycharm一共有两个版 ...
- Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) JAVA日志的前世今生 .NET MVC采用SignalR更新在线用户数 C#多线程编程系列(五)- 使用任务并行库 C#多线程编程系列(三)- 线程同步 C#多线程编程系列(二)- 线程基础 C#多线程编程系列(一)- 简介
Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) 一.前言 由于本篇文章较长,所以下面给出内容目录方便跳转阅读,当然也可以用博客页面最右侧的文章目录导航栏进行跳转查阅. 一.前言 ...
随机推荐
- compiz隐藏最大化窗口标题栏
xfwm换了compiz试试,还行,挺方便.就是这个隐藏最大化窗口的标题栏没有现成的ui设置项,google到如下解决方案: 修改后立即生效. https://planetkris.com/2009/ ...
- JavaScript常用技巧之字符串操作
1.首字母大写 str.replace(/\b\w+/g, function (word) { return word.substring(0, 1).toLowerCase() + word.sub ...
- 【网页布局基础】css布局学习总结
三种定位机制 1.标准文档流:从上到下,从左到右输出文档内容 2.浮动 3.绝对定位 需要注意的是块级元素如div p ul 等 行级元素如span strong img input等 块级元素与行级 ...
- UDP协议解析 以及和TCP协议的区别
UDP(User Data Protocol)是传输层的用户数据报协议,有复用和分用以及差错检测的功能. 1) 多路复用(针对发送主机):从不同套接字收集数据块,并为每个数据块封装上首部信息,生成报文 ...
- 读取Properties
package com.infotech.common.util; import java.io.FileNotFoundException; import java.io.IOException; ...
- leetcood学习笔记-26-删除排序数组中的重复项
题目描述: 第一次提交: class Solution: def removeDuplicates(self, nums) -> int: for i in range(len(nums)-1, ...
- Delphi 左键代替右键
Delphi 左键代替右键: var Pt: TPoint; begin GetCursorPos(Pt); PopupMenu1.Popup(Pt.X, Pt.Y); end;
- QT之sqlite连接
啥也没做,按说明直接啪啪写一堆代码 QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); //open datebase ...
- PHP ftp_get_option() 函数
定义和用法 The ftp_get_option() 函数返回 FTP 连接的各种运行时选项. 语法 ftp_get_option(ftp_connection,option) 参数 描述 ftp_c ...
- Delphi实现提取可执行文件内部所有图标
本实例实现的功能是能够从用户选择的可执行文件(后缀名为exe)中提取所有图标并且显示在窗体上. 在窗体中添加TImage 组件.TOpenDialog组件和TButton组件,TImage组件充当显示 ...