如何模仿Apple Map的翻译表视图?

时间:2018-07-15 00:21:33

标签: ios swift uitableview uiscrollview

我正在制作一个以类似于苹果地图的方式返回场地(如餐厅)的应用程序,即最初隐藏在屏幕外的表格视图,然后在要显示表格视图的内容时在其他内容之上移动。
这是到目前为止我得到的:

enter image description here

您会注意到,向后拉表格视图以显示其背后的地图时,表格视图不会以一种流畅的运动向下移动。实际上,当表格视图到达其“顶部”时,您会注意到右侧的滚动条是可见的,但视图没有移动。这是因为在录制时,我向下拖动,但视图需要一些时间才能开始实际向下移动。我将解释为什么会有这种延迟,但首先将这种行为与Apple maps表视图的行为进行比较:
enter image description here

请注意,Apple Maps表格视图从转换视图本身到滚动滚动视图的过渡都是流畅的。当视图的minY达到某个点时,视图向上的转换将转换为滚动视图的向下滚动(反之亦然)。这是在用户向上滑动整个过程中完成的。

现在,我将解释创建翻译滚动视图的过程。滚动视图本身是一个UITableViewController,嵌入在地图视图控制器的容器视图中。
enter image description here

包含容器视图的视图具有平移手势识别器。当平移手势识别器的状态为UIGestureRecognizerState.ended,即拖动已结束时,它将检查容器视图相对于预定Y坐标的minY。如果minY小于预定的Y坐标,则它将对容器视图进行动画处理,以将其minY捕捉到该Y坐标。如果minY略大于预定的Y坐标,情况也是相同的,在这种情况下,容器视图将向上动画,因此其minY将捕捉到此预定的Y坐标。 enter image description here

一旦视图捕捉到此位置,嵌入式UITableViewController的“ .isScrollEnabled”属性(最初设置为false)现在设置为true。现在启用嵌入式表格视图滚动后,与平移容器视图相反,用户执行的拖动将滚动表格视图。要撤消此操作,我已经做到这一点,以便当表视图到达其滚动的顶部时,其“ .isScrollEnabled”属性将设置回false。这意味着用户进行的任何拖动动作都将平移视图,而不是滚动表格视图。这不会在滚动和翻译Apple地图的方式之间过渡时产生流动性。用户实际上必须在该区域上执行多次拖动才能从滚动过渡到平移; Apple Maps可以一键完成。
这是我在容器视图的父视图控制器中使用的代码:

  • 将容器视图卡入到位
  • 将嵌入式表视图控制器的.isScrollEnabled属性更改为true

    @objc func handlePan(sender: UIPanGestureRecognizer) {
    
    let resultView = self.resultView
    let translation = sender.translation(in: view)
    
    switch sender.state {
    case .began, .changed:
    
        resultView?.center = CGPoint(x: (resultView?.center.x)!, y: (resultView?.center.y)! + translation.y)
        sender.setTranslation(CGPoint.zero, in: view)
    
        if (resultView?.frame.minY)! <= self.view.frame.height - self.searchView.frame.height - self.view.safeAreaInsets.bottom && self.resultView.frame.height >= (self.searchView.frame.height + self.view.safeAreaInsets.bottom) {
            resultView?.frame.size.height -= translation.y
        }
    
    case .ended:
        if (resultView?.frame.minY)! > self.view.frame.height * 0.40 {
    
            self.resultTableViewController?.tableView.isScrollEnabled = false
    
        } else {
    
            self.resultTableViewController?.tableView.isScrollEnabled = true
    
        }
    
        if (resultView?.frame.minY)! <= view.frame.height * 0.40 {
    
            let difference =  (resultView?.frame.minY)! - (view.frame.height * 0.05)
    
            UIView.animate(withDuration: 0.25) {
                resultView?.center = CGPoint(x: (resultView?.center.x)!, y: (resultView?.center.y)! - difference)
                resultView?.frame.size.height += difference
                self.view.layoutIfNeeded()
            }
            dismissed = false
        } else if (resultView?.frame.minY)! >= view.frame.height * 0.75 {
            let difference = (view.frame.height - dismissResultButton.frame.height - view.safeAreaInsets.bottom) - (resultView?.frame.minY)!
    
            UIView.animate(withDuration: 0.25, animations: {
                resultView?.center = CGPoint(x: (resultView?.center.x)!, y: (resultView?.center.y)! + difference)
                self.resultView.frame.size.height = self.searchView.frame.size.height + self.view.safeAreaInsets.bottom
                self.view.layoutIfNeeded()
            })
            dismissed = true
        } else if (resultView?.frame.minY)! >= view.frame.height * 0.40 {
            let difference = mapView.frame.height - (resultView?.frame.minY)!
    
            UIView.animate(withDuration: 0.25) {
                resultView?.center = CGPoint(x: (resultView?.center.x)!, y: (resultView?.center.y)! + difference)
                self.resultView.frame.size.height = self.searchView.frame.size.height + self.view.safeAreaInsets.bottom
                self.view.layoutIfNeeded()
            }
            dismissed = false
        }
    
        sender.setTranslation(CGPoint.zero, in: view)
    default:
        break
    }
    
    }
    

现在,在UITableViewController中:

  • 确保滚动视图仅在滚动底部时反弹(应该锁定,然后在到达顶部时转换为容器转换)
  • 将.isScrollEnabled更改回false并允许在拖动时进行容器视图翻译
  • override func scrollViewDidScroll(_ scrollView: UIScrollView) {
        scrollView.bounces = (scrollView.contentOffset.y > 0)
    }
    
    override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        let translation = scrollView.panGestureRecognizer.translation(in: scrollView.superview!)
        if translation.y > 0 {
            if scrollView.contentOffset.y == 0 {
                tableView.isScrollEnabled = false
            }
        }
    }
    

    这是我想出的最好办法,可以尝试通过Apple maps表视图复制此行为。任何帮助/建议将不胜感激。



    附言如果您想进一步分解该项目的github,请执行以下操作:https://github.com/ChopinDavid/What2Do

    0 个答案:

    没有答案