告诉 UIPageViewController 何时滚动(用于图像的视差滚动)
Posted
技术标签:
【中文标题】告诉 UIPageViewController 何时滚动(用于图像的视差滚动)【英文标题】:Tell When a UIPageViewController is Scrolling (for Parallax Scrolling of an Image) 【发布时间】:2013-04-28 21:41:52 【问题描述】:我正在尝试制作类似于新雅虎天气应用程序中的效果。基本上,UIPageViewController
中的每个页面都有一个背景图片,当滚动浏览页面视图时,图片的位置只滚动大约一半的速度。我该怎么做?我想我可以在UIPageViewController
中使用某种委托方法来获取当前偏移量,然后像这样更新图像。唯一的问题是我无论如何都无法判断UIPageViewController
是否正在滚动!有没有办法呢?谢谢!
【问题讨论】:
【参考方案1】:for (UIView *view in self.pageViewController.view.subviews)
if ([view isKindOfClass:[UIScrollView class]])
[(UIScrollView *)view setDelegate:self];
这使您可以访问所有标准滚动视图 API 方法。 而且这没有使用私有的 Apple API。
我添加了遍历子视图,以 100% 找到UIPageViewController
的内部滚动视图
警告:
小心 scrollview.contentOffset。当控制器滚动到新页面时它会重置
如果您需要持久性scrollview
偏移跟踪和类似的东西,最好使用UICollectionViewController
与集合视图本身大小的单元格并启用分页。
【讨论】:
如果 Apple 改变他们的页面视图控制器的架构,你就完蛋了。 @VanDuTran 同意,但在那之前,一切都很好,而且似乎是最好的方法。我没有看到其他选择 对我来说这不是第一个子视图,而是第二个子视图。这段代码做到了:if([self.pageVC.view.subviews[1] respondsToSelector:@selector(setDelegate:)]) [self.pageVC.view.subviews[1] setDelegate:self];
这个问题是它没有给出scrollview.contentOffset的标准结果。它会在每个新页面重置。
这不仅仅是Apple的chnages,而是你分配了新的委托,所以如果UIPageViewController的内部实现使用它,你会破坏它。【参考方案2】:
我会这样做:
Objective-C
for (UIView *v in self.pageViewController.view.subviews)
if ([v isKindOfClass:[UIScrollView class]])
((UIScrollView *)v).delegate = self;
并实现这个协议
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
斯威夫特
for view in self.pageViewController.view.subviews
if let scrollView = view as? UIScrollView
scrollView.delegate = self
并实现这个协议
func scrollViewDidScroll(scrollView: UIScrollView)
【讨论】:
感谢您提供的 Swift 代码【参考方案3】:我的猜测是它不是 UIPageViewController,而是分页的UIScrollView。 UIScrollView 确实为您提供了一个不断重复的委托方法,用于跟踪滚动发生时发生的事情。
或者,您可能能够访问 UIPageViewController 秘密使用的分页 UIScrollView,但您可能会破坏某些东西,我不确定 Apple 会怎么想。
【讨论】:
必须有一种方法可以使用 UIPageViewController 执行此操作。如果我使用它,它只会简化一切。 Yahoo App 看起来也使用了 UIPageViewController。有没有办法从 UIViewController 本身获取屏幕上的位置? UIPageViewController 基本上不就是一个花哨的 UIScrollView 吗? 这对你来说可能更简单,但我向你保证,在滚动式 UIPageViewController 存在之前,仅使用 UIScrollView 我们就已经在做滚动式 UIPageViewController 之类的事情了。有完整的 WWDC 视频专门用于解释如何做到这一点。 花哨但不透明。正如我所说,您可以沿着视图层次结构向下工作并找到滚动视图。但您可能不应该这样做。 有没有办法可以将滚动视图放在顶部并从中读取数据?【参考方案4】:使用@Paul 的 sn-p -
for (UIView *v in self.pageViewController.view.subviews)
if ([v isKindOfClass:[UIScrollView class]])
((UIScrollView *)v).delegate = self;
实现这个协议:-(void)scrollViewDidScroll:(UIScrollView *)scrollView
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
CGPoint point = scrollView.contentOffset;
float percentComplete;
percentComplete = fabs(point.x - self.view.frame.size.width)/self.view.frame.size.width;
NSLog(@"percentComplete: %f", percentComplete);
这为您提供了卷轴的完成百分比。编码愉快!
【讨论】:
【参考方案5】:在 Swift 3 中你可以写得更短:
if let scrollView = self.pageViewController.view.subviews.first(where: $0 is UIScrollView ) as? UIScrollView
scrollView.delegate = self
【讨论】:
【参考方案6】:extension UIPageViewController
var scrollView: UIScrollView?
return view.subviews.filter $0 is UIScrollView .first as? UIScrollView
使用:
pageController.scrollView?.delegate = self
【讨论】:
【参考方案7】:您正在寻找的称为视差滚动,您可以找到几个可以帮助您解决此问题的库。
编辑:马特是对的,这不是一个答案,只是一个提示。无论如何,让我们完成它:
要为位于 UIPageViewController 后面的背景图像设置动画,您应该使用它提供的委托方法:
-[id<UIPageViewControllerDelegate> pageViewController:willTransitionToViewControllers:]
-[id<UIPageViewControllerDelegate> pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:]
通过这两种方法,您可以计算滚动百分比(您应该将控制器存储在数组中,以了解您滚动到哪个控制器并获取百分比)
【讨论】:
你如何从中得到百分比? 您应该使用-[NSArray indexOfObject:]
获得搜索到的视图控制器的位置,然后您可以做一些基本的数学运算来获得该索引相对于-[NSArray count]
的百分比
这不是我真正想要的。每个视图控制器内部都有自己的 UIImage。我需要逐像素控制图像的位置,使用这样的百分比根本行不通。
mm 你可以查看-[UIPageViewController gestureRecognizers]
寻找UIPanGestureRecognizer
并使用它的方法准确(合法地)知道当前的运动是什么。【参考方案8】:
您不应该更改页面视图控制器的滚动视图的委托:它可能会破坏其正常行为和/或以后不受支持。
相反,您可以:
向页面视图控制器的视图添加平移手势:
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panRecognized(gesture:)))
view.addGestureRecognizer(panGesture)
panGesture.delegate = self
添加新函数以了解视图是如何滚动的。
@objc func panRecognized(gesture: UIPanGestureRecognizer)
// Do whatever you need with the gesture.translation(in: view)
将您的 ViewController 声明为 UIGestureRecognizerDelegate
。
实现这个功能:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
return true
【讨论】:
以上是关于告诉 UIPageViewController 何时滚动(用于图像的视差滚动)的主要内容,如果未能解决你的问题,请参考以下文章
UIPageViewController 使用 Storyboard 和 Xcode 4.5
避免用户使用 UIPageViewController 滚动到索引 -1 和 2
iOS UIPageViewController 页面控件不同步
小白科普:侧链Plasma 和 Sharding 三者有何区别?V神告诉你!