前言
以前公司做過一個tableView嵌套tableView滾動的功能實(shí)現(xiàn)彻桃。今天特意重新的整理了一下這個功能的實(shí)現(xiàn)。
功能需求說明:
- 頂部是一個banner圖片
- 側(cè)邊欄
- 內(nèi)容tableView
具體的實(shí)現(xiàn)效果圖如下:
功能需求.gif
這個功能一開始的實(shí)現(xiàn)的方式是采用的ScrollView嵌套TableView實(shí)現(xiàn)的晾蜘。又重新的寫了一下這個功能模塊邻眷。這次采用的是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)建一個主控制器
MainController
- 給當(dāng)前視圖添加一個是否可以滾動的參數(shù)
canScroll
肆饶。關(guān)于這個參數(shù)的使用后面再做說明 - 控制器創(chuàng)建一個tableView
- 給tableView實(shí)現(xiàn)相關(guān)的代理方法
- tableViewCell的數(shù)量為1
- 給tableView設(shè)置headerView
- tableView設(shè)置SectionHeaderView改衩。這個地方的headerView是為了滿足多個標(biāo)題而準(zhǔn)備的。如果不需要這個標(biāo)題只需要一個banner的話完全可以使用ScrollView+tableView來實(shí)現(xiàn)這個功能就可以了驯镊。
特別注意:
關(guān)于Cell高度的設(shè)置應(yīng)該是一個屏幕的高度 - SectionHeaderView的高度葫督。或者說是你當(dāng)前tableView的高度 -SectionHeaderView的高度板惑。當(dāng)前tableView的ContentSize
的大小應(yīng)該是tableHeaderView的高度+tableView的高度 - SectionHeaderView的高度
2.自定義tableViewCell
我這里要實(shí)現(xiàn)左右滑動切換tableView所以用到了一個ScrollView橄镜。如果沒有多個標(biāo)題的需求的話是不需要這個ScrollView的
- 創(chuàng)建一個ScrollView
- ScrollView的高度值和你當(dāng)前Cell的高度一致,寬度根據(jù)你的標(biāo)題個數(shù)設(shè)置冯乘。我這里是兩個標(biāo)題所以我的寬度應(yīng)該是
屏幕寬*2
- 創(chuàng)建兩個tableView添加到ScrollView上面去洽胶。tableView的高度和ScrollView高度一致。寬度是屏幕寬
至此頁面的樣式寫完了往湿。
這個時候運(yùn)行程序的時候會發(fā)現(xiàn)上面的tableView和下面的tableView的滾動存在沖突
3.解決tableView嵌套滾動沖突的問題
- 自定義一個新的tableView
- tableView實(shí)現(xiàn)
UIGestureRecognizerDelegate
- tableView實(shí)現(xiàn)
UIGestureRecognizerDelegate
中的這個方法gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
- 判斷方法中
gestureRecognizer
和otherGestureRecognizer
是否為UIPanGestureRecognizer
是的話返回true
妖异,不是的話返回false
惋戏。這個地方其實(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)絲滑滾動
我相信很多第一次接觸這個功能的時候领追,很多人想到的方法是利用tableView的ScrollEnable屬性來解決滾動沖突的問題
。千萬不要這樣做响逢。千萬不要這樣做绒窑。千萬不要這樣做。一旦你這么做了的話舔亭,后果就是當(dāng)你發(fā)現(xiàn)要切換兩個視圖的ScrollEnable屬性的時候會出現(xiàn)明顯的卡頓情況些膨。
正確的做法應(yīng)該是設(shè)置tableView的contentOffset的值
- 設(shè)置
MainController
的scrollViewDidScroll
方法,當(dāng)滾動高度大于等于tableHeaderView
高度的時候設(shè)置tableView的contentOffsetY的高度一直為tableHeaderView
的高度钦铺。一開始設(shè)置的呢個canScroll
屬性就起作用了订雾。具體代碼如下:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//如果高度大于等于tableHeaderView的高度的時候
if scrollView.contentOffset.y >= HEADER_HEIGHT{
//設(shè)置ContentOffsetY的高度為tableHeaderView的高度
scrollView.contentOffset = CGPoint(x: 0, y: HEADER_HEIGHT)
if self.canScroll {
self.canScroll = false//設(shè)置是否可以滾動的參數(shù)為false
//發(fā)送通知給子tableView。設(shè)置子tableView的可滾動屬性為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的滾動事件矛洞。具體代碼如下:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//開始的時候子視圖是無法滾動的 canScroll屬性為false
if !self.canScroll{
scrollView.contentOffset = CGPoint.zero
}
//如果子視圖的滾動高度小于等于0證明子視圖滾動到了頭部
if scrollView.contentOffset.y <= 0 {
self.canScroll = false
//給主視圖的tableView發(fā)送改變是否可以滾動的狀態(tài)洼哎。讓主視圖的tbaleView可以滾動
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)化由簡書用戶@a1203302261提供。在此只做總結(jié)方便下載