我正在制作一个以类似于苹果地图的方式返回场地(如餐厅)的应用程序,即最初隐藏在屏幕外的表格视图,然后在要显示表格视图的内容时在其他内容之上移动。
这是到目前为止我得到的:
您会注意到,向后拉表格视图以显示其背后的地图时,表格视图不会以一种流畅的运动向下移动。实际上,当表格视图到达其“顶部”时,您会注意到右侧的滚动条是可见的,但视图没有移动。这是因为在录制时,我向下拖动,但视图需要一些时间才能开始实际向下移动。我将解释为什么会有这种延迟,但首先将这种行为与Apple maps表视图的行为进行比较:
请注意,Apple Maps表格视图从转换视图本身到滚动滚动视图的过渡都是流畅的。当视图的minY达到某个点时,视图向上的转换将转换为滚动视图的向下滚动(反之亦然)。这是在用户向上滑动整个过程中完成的。
现在,我将解释创建翻译滚动视图的过程。滚动视图本身是一个UITableViewController,嵌入在地图视图控制器的容器视图中。
包含容器视图的视图具有平移手势识别器。当平移手势识别器的状态为UIGestureRecognizerState.ended,即拖动已结束时,它将检查容器视图相对于预定Y坐标的minY。如果minY小于预定的Y坐标,则它将对容器视图进行动画处理,以将其minY捕捉到该Y坐标。如果minY略大于预定的Y坐标,情况也是相同的,在这种情况下,容器视图将向上动画,因此其minY将捕捉到此预定的Y坐标。
一旦视图捕捉到此位置,嵌入式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中:
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