UIPageViewController看这篇就够了
先说初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | - (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; } |
然后填充内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //填充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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #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如下
1 2 3 4 5 6 7 8 9 10 | 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如下
1 2 3 4 | ReadingViewController.m[88] push0 ReadingViewController.m[102] before=0 ReadingViewController.m[121] after=0 ReadingViewController.m[88] push1 |
虽然拖动完成的代理方法没有执行。但是 viewControllerAfterViewController方法触发,加载好了下一页的ViewController内容。
然后往右拖动会提前加载第三页的内容Log如下
1 2 3 4 5 6 7 | 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如下
1 2 3 4 5 6 7 8 9 10 11 12 | 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+1< 10) { self.pageNumberLB.text = [NSString stringWithFormat:@"0%ld/%ld",_animationIndex+1,_maxPage]; }else{ self.pageNumberLB.text = [NSString stringWithFormat:@"%ld/%ld",_animationIndex+1,_maxPage]; } } }
其实只用上面那个就可以基本满足,不过会有轻微的拖动一下虽然没有翻页成功也会改变页码字符的现象,配合下方的方法就完美了。
OVER
2019-10-31更新
最近一个项目也用到了PageViewController,开始是UIPageViewControllerTransitionStylePageCurl,后来想用UIPageViewControllerTransitionStyleScroll,发现坑太多了,改成了UICollectionView去代替。
如果style是UIPageViewControllerTransitionStyleScroll,不推荐用PageViewController,坑太多了!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!