Ios 视差视图滚动(类似雅虎天气)

Ios 视差视图滚动(类似雅虎天气),ios,graphics,parallax,Ios,Graphics,Parallax,严格来说,这不是一个编程问题,而是更多的“如何完成这个”问题 我很好奇(正在开发一个可能需要这个功能的应用程序)左右视差滚动是如何实现的。要确切了解我的意思,请查看雅虎天气应用程序(它是免费的,不用担心) 他们是只使用一个视图控制器,还是为显示的每个视图使用单独的控制器? 实现这一点最简单的方法是什么?我已经找到了某种解释,但他们什么时候从服务器上获取信息?是在视图更改时还是在应用程序启动时 任何关于如何实现这种滚动的信息都将不胜感激。其实很简单: 子类UIScrollView 添加UIVie

严格来说,这不是一个编程问题,而是更多的“如何完成这个”问题

我很好奇(正在开发一个可能需要这个功能的应用程序)左右视差滚动是如何实现的。要确切了解我的意思,请查看雅虎天气应用程序(它是免费的,不用担心)

他们是只使用一个视图控制器,还是为显示的每个视图使用单独的控制器?
实现这一点最简单的方法是什么?我已经找到了某种解释,但他们什么时候从服务器上获取信息?是在视图更改时还是在应用程序启动时


任何关于如何实现这种滚动的信息都将不胜感激。

其实很简单:

  • 子类UIScrollView
  • 添加UIView*视差视图;as@property
  • 将CGFloat视差因子添加为@property
  • 覆盖布局子视图
  • 调用super,然后使用self.scrollOffset*parallaxFactor定位视差视图
就这样

我自己制作了一个多功能的UIScrollView子类,非常简单易用,非常适合这种情况!在GitHub上获取它:


祝你好运

我实现了一个基于标准UIPageViewController子类和视差效果的自动布局约束的小型原型。 如果您想看一看,它的文档记录非常完整:

简而言之,视差的核心是通过
scrollViewDidScroll
delegate方法完成的:

extension PageViewController: UIScrollViewDelegate {

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let screenWidth = scrollView.bounds.width
        /*
         In a UIPageViewController, the initial contentOffset.x is not 0, but equal to the screen width
         (so that the offset goes between (1 * screenWidth) and 0 when going to the previous view controller, 
         and from (1 * screenWidth) to (2 * screenWidth) when going to the next view controller).
         Also, it's reset to the screenWidth when the scroll to a previous or next view controller is complete.
         Therefore, we calculate a new 'horizontalOffset' starting at 0, and going:
         - negative from 0 to (-screenWidth/2) when scrolling to the next view controller,
         - and from 0 to (screenWidth/2) when scrolling to the previous view controller.
         */
        let horizontalOffset = (scrollView.contentOffset.x - screenWidth)/2

        // Special case: initial situation, or when the horizontalOffset is reset to 0 by the UIPageViewController.
        guard horizontalOffset != 0 else {
            previousPageController?.offsetBackgroundImage(by: screenWidth/2)
            currentPageController?.offsetBackgroundImage(by: 0)
            nextPageController?.offsetBackgroundImage(by: -screenWidth/2)
            return
        }

        // The background image of the current page controller should always be offset by the horizontalOffset (which may be positive or negative)
        guard let currentPageController = currentPageController else { return }
        currentPageController.offsetBackgroundImage(by: horizontalOffset)

        if horizontalOffset > 0 { // swiping left, to the next page controller

            // The background image of the next page controller starts with an initial offset of (-screenWidth/2), then we apply the (positive) horizontalOffset
            if let nextPageController = nextPageController {
                let nextOffset = -screenWidth/2 + horizontalOffset
                nextPageController.offsetBackgroundImage(by: nextOffset)
            }
        } else { // swiping right, to the previous page controller

            // The background image of the previous page controller starts with an initial offset of (+screenWidth/2), then we apply the (negative) horizontalOffset
            if let previousPageController = previousPageController {
                let previousOffset = screenWidth/2 + horizontalOffset
                previousPageController.offsetBackgroundImage(by: previousOffset)
            }
        }
    }
}

您不应该更改页面视图控制器的滚动视图的委托。它会破坏它的正常行为

相反,您可以:

  • 将平移手势添加到页面视图控制器的视图:

    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声明为
    UIgestureRecognitizerDelegate

  • 实现此功能:

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
    

  • 是的,这确实处理了可见部分。但是功能呢?例如,如果用户想要更新天气,他会下拉视图,并用最新的天气信息刷新视图。我怀疑他们是否使用
    if
    s来确定显示哪个视图。有什么想法吗?我刚刚做的东西是开源的!只需使用parallaxView.currentPageIndex:),但更好的是,为每个页面使用不同的垂直(简单块的视差)滚动视图,并在其中重新加载。(别忘了让手势识别器互相屏蔽):我今天试图让它打勾,但你忘了包括
    UIView+myExt.h
    。你能把它也贴出来吗?哦,对不起!!将立即添加它!看起来像个很棒的图书馆。很想在椰子荚上提供;)