UITableView上添加TableView,方便叙述将两个TableView编号,底层TableView为1,上层的TableView为2。
如图:
下拉时,当1未滑动到指定位置时2不单独滑动,跟随1滑动,当1滑动到指定位置时1不动2进行单独滑动。
上拉时,当2未滑动到顶部,1保持不动,当2滑动到顶部时1跟随着滑动。
首先
我们需要让两个1跟2同时响应滑动的手势
这样的话就需要在TableView签订手势识别代理
实现代理方法
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
Simultaneously:同时的
这个方法意思是,是否允许多个手势识别器同时识别,一个控件的手势识别后,是否阻断手势识别继续向下传递,默认为false,如果return true,响应者链上层触发手势后,如果下层也添加了相同手势,则会同样响应手势。
创建传递手势的TableView
import UIKit
class GestureTableView: UITableView, UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
然后
设计思路是在scrollViewDidScroll的代理方法中进行contentOffset的位置判断,处理两个TableView的滑动状态。
注意的是,处理TableView保持不动的方法不要用
tableView.isScrollEnable,
当滑动速度快时,位置判断会不生效。
改用
tableView.contentOffset = CGPoint(x: 0, y: X)
时时设置TableView的位置来控制滑动与停止。
另外两个TableView的状态信息需要共享,这里我用到了通知中心,互相发送状态改变的信号,作出响应的处理操作。
代码里有详细的注释:
import UIKit
class TableViewQTController: BaseViewController, UITableViewDelegate, UITableViewDataSource {
///tableview是否可以滑动
var canScroll: Bool = true
lazy var tableView: GestureTableView = {
let table = GestureTableView()
table.backgroundColor = .clear
table.delegate = self
table.dataSource = self
//取消tableView底部的线条
table.separatorStyle = .none
return table
}()
override func setViews() {
view.addSubview(tableView)
tableView.snp.makeConstraints {
$0.top.equalToSuperview().offset(statusBarH + 44)
$0.left.right.bottom.equalToSuperview()
}
tableView.register(TableQTTitleTableCell.self, forCellReuseIdentifier: "TableQTTitleTableCell")
tableView.register(TableInTabelCell.self, forCellReuseIdentifier: "TableInTabelCell")
addCenterNotification()
}
//注册通知中心 等待下层tabel发来状态改变
func addCenterNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(notificationAction), name: NSNotification.Name(rawValue: "botTable"), object: nil)
}
//收到通知进行操作
@objc func notificationAction() {
//收到下层table的通知,上层table可以开始滑动
self.canScroll = true
}
deinit {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "botTable"), object: nil)
}
//MARK: - Delegate
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let y = scrollView.contentOffset.y
if !canScroll {
//上层table保持不动
self.tableView.contentOffset = CGPoint(x: 0, y: 200)
}
/**
当contentOffset.y大于200时
上层的Table保持不动
并发送通知让下层table动
*/
if y >= 200 {
self.canScroll = false
self.tableView.contentOffset = CGPoint(x: 0, y: 200)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "topTable"), object: nil)
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 3 {
return S_H - statusBarH - bottomBarH - 100 - 44
}
return 100
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 3 {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableInTabelCell") as! TableInTabelCell
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableQTTitleTableCell") as! TableQTTitleTableCell
cell.titlab.text = "这是第\(indexPath.row)个cell"
if indexPath.row == 0 {
cell.contentView.backgroundColor = .red
}
if indexPath.row == 1 {
cell.contentView.backgroundColor = .green
}
if indexPath.row == 2 {
cell.contentView.backgroundColor = .yellow
}
return cell
}
}
}
class TableQTTitleTableCell: BaseTableViewCell {
let titlab = UILabel()
override func setViews() {
titlab.textColor = .black
titlab.font = SFONT(15)
contentView.addSubview(titlab)
titlab.snp.makeConstraints {
$0.left.equalToSuperview().offset(20)
$0.centerY.equalToSuperview()
}
}
}
class TableInTabelCell: BaseTableViewCell, UITableViewDataSource, UITableViewDelegate {
var canSroll: Bool = false
lazy var tableView: GestureTableView = {
let table = GestureTableView()
table.backgroundColor = .clear
table.delegate = self
table.dataSource = self
table.separatorStyle = .none
return table
}()
override func setViews() {
tableView.register(TableQTTitleTableCell.self, forCellReuseIdentifier: "TableQTTitleTableCell")
contentView.addSubview(tableView)
tableView.snp.makeConstraints {
$0.edges.equalToSuperview()
}
addCenterNotification()
}
//注册通知中心 等待上层table发来通知
func addCenterNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(notificationAction), name: NSNotification.Name(rawValue: "topTable"), object: nil)
}
//收到通知进行操作
@objc func notificationAction() {
//上层tabel滑动到指定位置后发来通知,下层table可以开始滑动了
self.canSroll = true
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let y = scrollView.contentOffset.y
if !canSroll {
//保持不动的操作
scrollView.contentOffset = CGPoint.zero
}
/**
当contentOffset.y <= 0 即table滑动到顶部时
table保持不动并向上层table发送通知
让其可以开始滑动
*/
if y <= 0 {
self.canSroll = false
scrollView.contentOffset = CGPoint.zero
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "botTable"), object: nil)
}
}
deinit {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "topTable"), object: nil)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableQTTitleTableCell") as! TableQTTitleTableCell
cell.contentView.backgroundColor = .lightGray
cell.titlab.text = "第\(indexPath.row)个"
return cell
}
}