前言
以前公司做過一個(gè)tableView嵌套tableView滾動(dòng)的功能實(shí)現(xiàn)。今天特意重新的整理了一下這個(gè)功能的實(shí)現(xiàn)。
功能需求說明:
- 頂部是一個(gè)banner圖片
- 側(cè)邊欄
- 內(nèi)容tableView
具體的實(shí)現(xiàn)效果圖如下:
功能需求.gif
這個(gè)功能一開始的實(shí)現(xiàn)的方式是采用的ScrollView嵌套TableView實(shí)現(xiàn)的。又重新的寫了一下這個(gè)功能模塊。這次采用的是tableView嵌套tableView實(shí)現(xiàn)的此功能。
特別說明
文章中實(shí)現(xiàn)的功能和此功能略有差異,但實(shí)現(xiàn)的思路是一樣的
具體實(shí)現(xiàn)
在說明實(shí)現(xiàn)方法之前先上一下現(xiàn)在的效果圖

效果圖.gif
功能實(shí)現(xiàn)部分1.創(chuàng)建一個(gè)主控制器
MainController
- 給當(dāng)前視圖添加一個(gè)是否可以滾動(dòng)的參數(shù)
canScroll。關(guān)于這個(gè)參數(shù)的使用后面再做說明 - 控制器創(chuàng)建一個(gè)tableView
- 給tableView實(shí)現(xiàn)相關(guān)的代理方法
- tableViewCell的數(shù)量為1
- 給tableView設(shè)置headerView
- tableView設(shè)置SectionHeaderView。這個(gè)地方的headerView是為了滿足多個(gè)標(biāo)題而準(zhǔn)備的。如果不需要這個(gè)標(biāo)題只需要一個(gè)banner的話完全可以使用ScrollView+tableView來實(shí)現(xiàn)這個(gè)功能就可以了。
特別注意:
關(guān)于Cell高度的設(shè)置應(yīng)該是一個(gè)屏幕的高度 - SectionHeaderView的高度?;蛘哒f是你當(dāng)前tableView的高度 -SectionHeaderView的高度。當(dāng)前tableView的ContentSize的大小應(yīng)該是tableHeaderView的高度+tableView的高度 - SectionHeaderView的高度
2.自定義tableViewCell
我這里要實(shí)現(xiàn)左右滑動(dòng)切換tableView所以用到了一個(gè)ScrollView。如果沒有多個(gè)標(biāo)題的需求的話是不需要這個(gè)ScrollView的
- 創(chuàng)建一個(gè)ScrollView
- ScrollView的高度值和你當(dāng)前Cell的高度一致,寬度根據(jù)你的標(biāo)題個(gè)數(shù)設(shè)置。我這里是兩個(gè)標(biāo)題所以我的寬度應(yīng)該是
屏幕寬*2 - 創(chuàng)建兩個(gè)tableView添加到ScrollView上面去。tableView的高度和ScrollView高度一致。寬度是屏幕寬
至此頁(yè)面的樣式寫完了。
這個(gè)時(shí)候運(yùn)行程序的時(shí)候會(huì)發(fā)現(xiàn)上面的tableView和下面的tableView的滾動(dòng)存在沖突
3.解決tableView嵌套滾動(dòng)沖突的問題
- 自定義一個(gè)新的tableView
- tableView實(shí)現(xiàn)
UIGestureRecognizerDelegate - tableView實(shí)現(xiàn)
UIGestureRecognizerDelegate中的這個(gè)方法gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool - 判斷方法中
gestureRecognizer和otherGestureRecognizer是否為UIPanGestureRecognizer是的話返回true,不是的話返回false。這個(gè)地方其實(shí)也可以直接返回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.實(shí)現(xiàn)絲滑滾動(dòng)
我相信很多第一次接觸這個(gè)功能的時(shí)候,很多人想到的方法是利用tableView的ScrollEnable屬性來解決滾動(dòng)沖突的問題。千萬不要這樣做。千萬不要這樣做。千萬不要這樣做。一旦你這么做了的話,后果就是當(dāng)你發(fā)現(xiàn)要切換兩個(gè)視圖的ScrollEnable屬性的時(shí)候會(huì)出現(xiàn)明顯的卡頓情況。
正確的做法應(yīng)該是設(shè)置tableView的contentOffset的值
- 設(shè)置
MainController的scrollViewDidScroll方法,當(dāng)滾動(dòng)高度大于等于tableHeaderView高度的時(shí)候設(shè)置tableView的contentOffsetY的高度一直為tableHeaderView的高度。一開始設(shè)置的呢個(gè)canScroll屬性就起作用了。具體代碼如下:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//如果高度大于等于tableHeaderView的高度的時(shí)候
if scrollView.contentOffset.y >= HEADER_HEIGHT{
//設(shè)置ContentOffsetY的高度為tableHeaderView的高度
scrollView.contentOffset = CGPoint(x: 0, y: HEADER_HEIGHT)
if self.canScroll {
self.canScroll = false//設(shè)置是否可以滾動(dòng)的參數(shù)為false
//發(fā)送通知給子tableView。設(shè)置子tableView的可滾動(dòng)屬性為true
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ChilderNotice"), object: nil)
}
}else{
if !self.canScroll {
scrollView.contentOffset = CGPoint(x: 0, y: HEADER_HEIGHT)
}
}
}
- 設(shè)置子tableView的滾動(dòng)事件。具體代碼如下:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//開始的時(shí)候子視圖是無法滾動(dòng)的 canScroll屬性為false
if !self.canScroll{
scrollView.contentOffset = CGPoint.zero
}
//如果子視圖的滾動(dòng)高度小于等于0證明子視圖滾動(dòng)到了頭部
if scrollView.contentOffset.y <= 0 {
self.canScroll = false
//給主視圖的tableView發(fā)送改變是否可以滾動(dòng)的狀態(tài)。讓主視圖的tbaleView可以滾動(dòng)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "mainNotice"), object: nil)
}
}
5.完整的代碼下載地址
6.感謝a1203302261提供的代碼優(yōu)化

效果圖1.png

效果圖2.png

效果圖3.png
百度網(wǎng)盤:9vxh
github
此優(yōu)化由簡(jiǎn)書用戶@a1203302261提供。在此只做總結(jié)方便下載
