调整含UITableView的UIView的topAnchor时,如何禁止表视图滚动?
解决方案
要实现你需要的交互逻辑,核心是通过状态跟踪和滚动事件拦截,区分「视图上移/恢复阶段」和「表格正常滚动阶段」,在合适的时机禁止表格自身滚动,只调整视图位置。以下是具体实现步骤和代码:
1. 定义状态变量
在父UIViewController中添加状态标记,用于跟踪当前交互阶段:
// 标记包含表格的视图是否已顶到屏幕顶部 private var isViewAtTop = false // 标记是否正在恢复视图到初始位置(从顶部下拉时) private var isRestoringView = false // 视图初始的topAnchor常量(即上方taskView的高度) private let initialTopConstant: CGFloat // 在初始化或viewDidLoad中赋值 initialTopConstant = taskViewHeight
2. 重写滚动事件处理
将父控制器设为UITableView的代理,直接处理UIScrollViewDelegate方法,替代原有的eventHandler传递逻辑(更直接可控):
extension YourParentViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { // 全局禁止表格弹簧效果,避免干扰视图移动逻辑 scrollView.bounces = false let offsetY = scrollView.contentOffset.y // 场景1:正在恢复视图到初始位置 if isRestoringView { // 强制表格保持在顶部,禁止自身滚动 scrollView.contentOffset = .zero // 根据下拉偏移量逐步恢复视图topAnchor let newConstant = min(todosTableTopAnchor.constant - offsetY, initialTopConstant) todosTableTopAnchor.constant = newConstant view.layoutIfNeeded() // 恢复完成后重置状态 if newConstant >= initialTopConstant { isRestoringView = false isViewAtTop = false } return } // 场景2:视图未顶到顶部,正在上移 if !isViewAtTop { // 计算新的topAnchor常量(最小为0,即顶到顶部) let newConstant = max(initialTopConstant - offsetY, 0) todosTableTopAnchor.constant = newConstant view.layoutIfNeeded() // 强制表格保持在顶部,禁止自身滚动 scrollView.contentOffset = .zero // 检查是否已顶到顶部,切换状态 if newConstant <= 0 { isViewAtTop = true } } // 场景3:视图已顶到顶部,允许表格正常滚动 else { // 当表格滚动回顶部并继续下拉时,进入恢复视图状态 if offsetY <= 0 { isRestoringView = true scrollView.contentOffset = .zero } } } // 处理惯性滚动,优化动画流畅度 func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { // 向上快速滑动:直接将视图顶到顶部 if !isViewAtTop && velocity.y > 0 { UIView.animate(withDuration: 0.3) { self.todosTableTopAnchor.constant = 0 self.view.layoutIfNeeded() } completion: { _ in self.isViewAtTop = true scrollView.contentOffset = .zero } targetContentOffset.pointee = .zero } // 向下快速滑动:直接恢复视图到初始位置 else if isRestoringView && velocity.y < 0 { UIView.animate(withDuration: 0.3) { self.todosTableTopAnchor.constant = self.initialTopConstant self.view.layoutIfNeeded() } completion: { _ in self.isRestoringView = false self.isViewAtTop = false scrollView.contentOffset = .zero } targetContentOffset.pointee = .zero } } }
3. 初始设置
在viewDidLoad中完成初始约束和代理绑定:
override func viewDidLoad() { super.viewDidLoad() // 绑定表格代理 yourTableView.delegate = self // 初始设置topAnchor常量 todosTableTopAnchor.constant = initialTopConstant }
逻辑说明
- 视图上移阶段:表格未顶到顶部时,强制表格
contentOffset为0,仅调整视图的topAnchor,直到视图顶到屏幕顶部。 - 表格滚动阶段:视图顶到顶部后,允许表格正常滚动,直到滚动回顶部并继续下拉。
- 视图恢复阶段:下拉表格时,强制表格保持顶部,逐步将视图
topAnchor恢复到初始值,完成后重置状态。
内容的提问来源于stack exchange,提问作者martin wotterman
相关产品推荐
相关产品推荐

