前言
以前公司做过一个tableView嵌套tableView滚动的功能实现。今天特意重新的整理了一下这个功能的实现。
功能需求说明:
- 顶部是一个banner图片
- 侧边栏
- 内容tableView
具体的实现效果图如下:
功能需求.gif
这个功能一开始的实现的方式是采用的ScrollView嵌套TableView实现的。又重新的写了一下这个功能模块。这次采用的是tableView嵌套tableView实现的此功能。
特别说明
文章中实现的功能和此功能略有差异,但实现的思路是一样的
具体实现
在说明实现方法之前先上一下现在的效果图
![](https://img.haomeiwen.com/i23400597/eda3c765337e9f2c.gif)
功能实现部分
1.创建一个主控制器
MainController
- 给当前视图添加一个是否可以滚动的参数
canScroll
。关于这个参数的使用后面再做说明 - 控制器创建一个tableView
- 给tableView实现相关的代理方法
- tableViewCell的数量为1
- 给tableView设置headerView
- tableView设置SectionHeaderView。这个地方的headerView是为了满足多个标题而准备的。如果不需要这个标题只需要一个banner的话完全可以使用ScrollView+tableView来实现这个功能就可以了。
特别注意:
关于Cell高度的设置应该是一个屏幕的高度 - SectionHeaderView的高度。或者说是你当前tableView的高度 -SectionHeaderView的高度。当前tableView的ContentSize
的大小应该是tableHeaderView的高度+tableView的高度 - SectionHeaderView的高度
2.自定义tableViewCell
我这里要实现左右滑动切换tableView所以用到了一个ScrollView。如果没有多个标题的需求的话是不需要这个ScrollView的
- 创建一个ScrollView
- ScrollView的高度值和你当前Cell的高度一致,宽度根据你的标题个数设置。我这里是两个标题所以我的宽度应该是
屏幕宽*2
- 创建两个tableView添加到ScrollView上面去。tableView的高度和ScrollView高度一致。宽度是屏幕宽
至此页面的样式写完了。
这个时候运行程序的时候会发现上面的tableView和下面的tableView的滚动存在冲突
3.解决tableView嵌套滚动冲突的问题
- 自定义一个新的tableView
- tableView实现
UIGestureRecognizerDelegate
- tableView实现
UIGestureRecognizerDelegate
中的这个方法gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
- 判断方法中
gestureRecognizer
和otherGestureRecognizer
是否为UIPanGestureRecognizer
是的话返回true
,不是的话返回false
。这个地方其实也可以直接返回True
代码如下
import UIKit
class BaseTableView: UITableView , UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return gestureRecognizer.isKind(of: UIPanGestureRecognizer.self) && otherGestureRecognizer.isKind(of: UIPanGestureRecognizer.self)
}
}
4.实现丝滑滚动
我相信很多第一次接触这个功能的时候,很多人想到的方法是利用tableView的ScrollEnable属性来解决滚动冲突的问题
。千万不要这样做。千万不要这样做。千万不要这样做。一旦你这么做了的话,后果就是当你发现要切换两个视图的ScrollEnable属性的时候会出现明显的卡顿情况。
正确的做法应该是设置tableView的contentOffset的值
- 设置
MainController
的scrollViewDidScroll
方法,当滚动高度大于等于tableHeaderView
高度的时候设置tableView的contentOffsetY的高度一直为tableHeaderView
的高度。一开始设置的呢个canScroll
属性就起作用了。具体代码如下:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//如果高度大于等于tableHeaderView的高度的时候
if scrollView.contentOffset.y >= HEADER_HEIGHT{
//设置ContentOffsetY的高度为tableHeaderView的高度
scrollView.contentOffset = CGPoint(x: 0, y: HEADER_HEIGHT)
if self.canScroll {
self.canScroll = false//设置是否可以滚动的参数为false
//发送通知给子tableView。设置子tableView的可滚动属性为true
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ChilderNotice"), object: nil)
}
}else{
if !self.canScroll {
scrollView.contentOffset = CGPoint(x: 0, y: HEADER_HEIGHT)
}
}
}
- 设置子tableView的滚动事件。具体代码如下:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//开始的时候子视图是无法滚动的 canScroll属性为false
if !self.canScroll{
scrollView.contentOffset = CGPoint.zero
}
//如果子视图的滚动高度小于等于0证明子视图滚动到了头部
if scrollView.contentOffset.y <= 0 {
self.canScroll = false
//给主视图的tableView发送改变是否可以滚动的状态。让主视图的tbaleView可以滚动
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "mainNotice"), object: nil)
}
}
5.完整的代码下载地址
6.感谢a1203302261提供的代码优化
![](https://img.haomeiwen.com/i23400597/58c589d6512ce2fa.png)
![](https://img.haomeiwen.com/i23400597/96cdba01a51dce85.png)
![](https://img.haomeiwen.com/i23400597/5af8940b8af45716.png)
网友评论