前言
以前公司做過一個tableView嵌套tableView滾動的功能實現。今天特意重新的整理了一下這個功能的實現。
功能需求說明:
- 頂部是一個banner圖片
- 側邊欄
- 內容tableView
具體的實現效果圖如下:
功能需求.gif
這個功能一開始的實現的方式是采用的ScrollView嵌套TableView實現的。又重新的寫了一下這個功能模塊。這次采用的是tableView嵌套tableView實現的此功能。
特別說明
文章中實現的功能和此功能略有差異,但實現的思路是一樣的
具體實現
在說明實現方法之前先上一下現在的效果圖
效果圖.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提供的代碼優化
效果圖1.png
效果圖2.png
效果圖3.png