告诉 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神告诉你!

直播预告|长江大讲堂,DBA刘劲教授告诉你何时能走出新冠阴影

Swift Delegate 函数未执行