如何限制UITableView下拉至头部图片拉伸2倍高度后不再下拉?
实现UITableView可拉伸头部并限制拉伸上限
需求背景
我需要在UITableView上方实现一个可拉伸头部(Stretchy Header):用户下拉表格时图片会被拉伸,上拉或松开时图片恢复原尺寸。同时要求:当下拉使头部图片拉伸至原高度2倍后,阻止UITableView继续下拉,但仍允许上拉。
初始实现思路
首先用一个包含UIImageView(contentMode设为Aspect Fill)的UIView作为头部容器,容器下方放置UITableView。通过UIScrollView的代理方法来控制容器的拉伸与恢复:
extension MyViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { if scrollView.contentOffset.y < 0 && imageContainerViewHeightConstraint.constant < initialContainerImageViewHeight * 2 { imageContainerViewHeightConstraint.constant += abs(scrollView.contentOffset.y) } else if scrollView.contentOffset.y > 0 && imageContainerViewHeightConstraint.constant > initialContainerImageViewHeight { imageContainerViewHeightConstraint.constant -= abs(scrollView.contentOffset.y) } } func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { resetContainerViewSize() } func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { resetContainerViewSize() } } func resetContainerViewSize() { imageContainerViewHeightConstraint.constant = initialContainerImageViewHeight UIView.animate(withDuration: 0.4, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: { self.view.layoutIfNeeded() }, completion: nil) }
初始实现的问题
初始代码中,当头部拉伸到原高度的2倍后,虽然容器停止拉伸,但UITableView仍然可以继续下拉,不符合需求。
优化后的解决方案
参考Sh_Khan的建议,修改UIScrollView代理方法和重置方法,实现拉伸到上限后禁止继续下拉:
extension MyViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { if scrollView.contentOffset.y < 0 && imageContainerViewHeightConstraint.constant < initialContainerImageViewHeight * 2 { imageContainerViewHeightConstraint.constant += abs(scrollView.contentOffset.y) } else if scrollView.contentOffset.y < 0 && imageContainerViewHeightConstraint.constant >= initialContainerImageViewHeight * 2 { // 达到拉伸上限,固定容器高度并调整tableView位置,阻止继续下拉 imageContainerViewHeightConstraint.constant = initialContainerImageViewHeight * 2 view.layoutIfNeeded() dataTableView.frame = CGRect(x: 0.0, y: initialContainerImageViewHeight * 2, width: dataTableView.frame.size.width, height: dataTableView.frame.size.height) return } else if scrollView.contentOffset.y > 0 && imageContainerViewHeightConstraint.constant > initialContainerImageViewHeight { imageContainerViewHeightConstraint.constant -= abs(scrollView.contentOffset.y) } } func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { resetContainerViewSize() } func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { resetContainerViewSize() } } func resetContainerViewSize() { imageContainerViewHeightConstraint.constant = initialContainerImageViewHeight UIView.animate(withDuration: 0.4, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: { self.view.layoutIfNeeded() // 重置tableView位置到初始容器高度下方 self.dataTableView.frame = CGRect(x: 0.0, y: self.initialContainerImageViewHeight, width: self.dataTableView.frame.size.width, height: self.dataTableView.frame.size.height) }, completion: nil) }
关键改进点
- 当头部达到2倍原高度时,固定容器高度并实时调整UITableView的frame,使其紧贴容器底部,这样就阻止了继续下拉的空间
- 在重置容器尺寸的动画中,同步重置UITableView的位置,保证恢复后的布局正确
内容的提问来源于stack exchange,提问作者Pangu
相关产品推荐
相关产品推荐

